summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile61
-rw-r--r--src/abstract_hardware_model.h178
-rw-r--r--src/cuda-sim/cuda-math.h234
-rw-r--r--src/cuda-sim/cuda-sim.cc787
-rw-r--r--src/cuda-sim/cuda-sim.h49
-rw-r--r--src/cuda-sim/dram_callback.h6
-rw-r--r--src/cuda-sim/instructions.cc149
-rw-r--r--src/cuda-sim/memory.cc78
-rw-r--r--src/cuda-sim/memory.h1
-rw-r--r--src/cuda-sim/opcodes.def4
-rw-r--r--src/cuda-sim/ptx-stats.cc9
-rw-r--r--src/cuda-sim/ptx-stats.h6
-rw-r--r--src/cuda-sim/ptx.l11
-rw-r--r--src/cuda-sim/ptx.y11
-rw-r--r--src/cuda-sim/ptx_ir.cc72
-rw-r--r--src/cuda-sim/ptx_ir.h50
-rw-r--r--src/cuda-sim/ptx_loader.cc137
-rw-r--r--src/cuda-sim/ptx_loader.h5
-rw-r--r--src/cuda-sim/ptx_parser.cc61
-rw-r--r--src/cuda-sim/ptx_parser.h3
-rw-r--r--src/cuda-sim/ptx_sim.cc80
-rw-r--r--src/cuda-sim/ptx_sim.h144
-rw-r--r--src/debug.cc19
-rw-r--r--src/debug.h3
-rw-r--r--src/gpgpu-sim/Makefile209
-rw-r--r--src/gpgpu-sim/delayqueue.cc467
-rw-r--r--src/gpgpu-sim/delayqueue.h192
-rw-r--r--src/gpgpu-sim/dram.cc630
-rw-r--r--src/gpgpu-sim/dram.h129
-rw-r--r--src/gpgpu-sim/dram_sched.cc47
-rw-r--r--src/gpgpu-sim/gpu-cache.cc244
-rw-r--r--src/gpgpu-sim/gpu-cache.h36
-rw-r--r--src/gpgpu-sim/gpu-misc.h6
-rw-r--r--src/gpgpu-sim/gpu-sim.cc1583
-rw-r--r--src/gpgpu-sim/gpu-sim.h349
-rw-r--r--src/gpgpu-sim/icnt_wrapper.cc4
-rw-r--r--src/gpgpu-sim/icnt_wrapper.h4
-rw-r--r--src/gpgpu-sim/l2cache.cc940
-rw-r--r--src/gpgpu-sim/l2cache.h301
-rw-r--r--src/gpgpu-sim/mem_fetch.cc106
-rw-r--r--src/gpgpu-sim/mem_fetch.h44
-rw-r--r--src/gpgpu-sim/mem_latency_stat.cc189
-rw-r--r--src/gpgpu-sim/mem_latency_stat.h112
-rw-r--r--src/gpgpu-sim/scoreboard.cc66
-rw-r--r--src/gpgpu-sim/scoreboard.h33
-rw-r--r--src/gpgpu-sim/shader.cc4703
-rw-r--r--src/gpgpu-sim/shader.h1186
-rw-r--r--src/gpgpu-sim/stat-tool.cc7
-rw-r--r--src/gpgpu-sim/stat-tool.h1
-rw-r--r--src/gpgpu-sim/stats.h138
-rw-r--r--src/gpgpu-sim/visualizer.cc154
-rw-r--r--src/gpgpu-sim/visualizer.h2
-rw-r--r--src/gpgpu-sim/warp_tracker.cc471
-rw-r--r--src/gpgpu-sim/warp_tracker.h281
-rw-r--r--src/gpgpusim_entrypoint.cc65
-rw-r--r--src/gpgpusim_entrypoint.h8
-rw-r--r--src/intersim/Makefile2
-rw-r--r--src/intersim/interconnect_interface.cpp58
-rw-r--r--src/intersim/interconnect_interface.h12
-rw-r--r--src/intersim/statwraper.cpp9
-rw-r--r--src/intersim/statwraper.h3
61 files changed, 7392 insertions, 7557 deletions
diff --git a/src/Makefile b/src/Makefile
index 36b695a..453469c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -76,7 +76,7 @@ endif
ifneq ($(DEBUG),1)
OPTFLAGS += -O3
else
- CXXFLAGS += -D_GLIBCXX_DEBUG -DGLIBCXX_DEBUG_PEDANTIC
+ CXXFLAGS +=
endif
OPTFLAGS += -g3 -fPIC
@@ -106,3 +106,62 @@ option_parser.$(OEXT): option_parser.h
# DO NOT DELETE
+debug.o: debug.h abstract_hardware_model.h gpgpu-sim/shader.h
+debug.o: /usr/include/stdio.h /usr/include/features.h
+debug.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
+debug.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
+debug.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+debug.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h
+debug.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+debug.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
+debug.o: /usr/include/endian.h /usr/include/bits/endian.h
+debug.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
+debug.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+debug.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+debug.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
+debug.o: /usr/include/math.h /usr/include/bits/huge_val.h
+debug.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
+debug.o: /usr/include/assert.h cuda-sim/ptx.tab.h cuda-sim/dram_callback.h
+debug.o: gpgpu-sim/gpu-cache.h abstract_hardware_model.h
+debug.o: gpgpu-sim/delayqueue.h gpgpu-sim/stack.h gpgpu-sim/dram.h
+debug.o: gpgpu-sim/scoreboard.h gpgpu-sim/gpu-sim.h cuda-sim/ptx_sim.h
+debug.o: cuda-sim/dram_callback.h tr1_hash_map.h cuda-sim/opcodes.h
+debug.o: cuda-sim/opcodes.def cuda-sim/memory.h /usr/include/string.h
+debug.o: cuda-sim/cuda-sim.h cuda-sim/ptx_ir.h cuda-sim/ptx.tab.h
+debug.o: cuda-sim/ptx_sim.h option_parser.h
+gpgpusim_entrypoint.o: gpgpusim_entrypoint.h abstract_hardware_model.h
+gpgpusim_entrypoint.o: /usr/include/time.h /usr/include/bits/types.h
+gpgpusim_entrypoint.o: /usr/include/features.h /usr/include/sys/cdefs.h
+gpgpusim_entrypoint.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
+gpgpusim_entrypoint.o: /usr/include/gnu/stubs-64.h
+gpgpusim_entrypoint.o: /usr/include/bits/typesizes.h /usr/include/stdio.h
+gpgpusim_entrypoint.o: /usr/include/libio.h /usr/include/_G_config.h
+gpgpusim_entrypoint.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
+gpgpusim_entrypoint.o: /usr/include/bits/sys_errlist.h option_parser.h
+gpgpusim_entrypoint.o: /usr/include/stdlib.h /usr/include/sys/types.h
+gpgpusim_entrypoint.o: /usr/include/endian.h /usr/include/bits/endian.h
+gpgpusim_entrypoint.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
+gpgpusim_entrypoint.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+gpgpusim_entrypoint.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+gpgpusim_entrypoint.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
+gpgpusim_entrypoint.o: cuda-sim/cuda-sim.h abstract_hardware_model.h
+gpgpusim_entrypoint.o: cuda-sim/dram_callback.h cuda-sim/ptx_ir.h
+gpgpusim_entrypoint.o: /usr/include/assert.h cuda-sim/ptx.tab.h
+gpgpusim_entrypoint.o: cuda-sim/ptx_sim.h cuda-sim/memory.h
+gpgpusim_entrypoint.o: /usr/include/string.h option_parser.h
+gpgpusim_entrypoint.o: cuda-sim/ptx_parser.h gpgpu-sim/gpu-sim.h
+gpgpusim_entrypoint.o: gpgpu-sim/icnt_wrapper.h
+option_parser.o: /usr/include/stdio.h /usr/include/features.h
+option_parser.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
+option_parser.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
+option_parser.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+option_parser.o: /usr/include/libio.h /usr/include/_G_config.h
+option_parser.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
+option_parser.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h
+option_parser.o: /usr/include/sys/types.h /usr/include/time.h
+option_parser.o: /usr/include/endian.h /usr/include/bits/endian.h
+option_parser.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
+option_parser.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+option_parser.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+option_parser.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
+option_parser.o: /usr/include/assert.h /usr/include/string.h option_parser.h
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 9762674..c2f5b1a 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -1,37 +1,27 @@
#ifndef ABSTRACT_HARDWARE_MODEL_INCLUDED
#define ABSTRACT_HARDWARE_MODEL_INCLUDED
-#ifdef __cplusplus
-
-#if !defined(__VECTOR_TYPES_H__)
-struct dim3 {
- unsigned int x, y, z;
-};
-#endif
-
-class core_t {
-public:
- virtual ~core_t() {}
- virtual void set_at_barrier( unsigned cta_id, unsigned warp_id ) = 0;
- virtual void warp_exit( unsigned warp_id ) = 0;
- virtual bool warp_waiting_at_barrier( unsigned warp_id ) = 0;
-};
-
-#define MAX_REG_OPERANDS 8
-extern unsigned int warp_size;
-#endif
+#include <string.h>
+#include <stdio.h>
+typedef unsigned long long new_addr_type;
typedef unsigned address_type;
typedef unsigned addr_t;
-// these are operations the timing model can see
-#define NO_OP -1
-#define ALU_OP 0x01000
-#define SFU_OP 0x02000
-#define LOAD_OP 0x04000
-#define STORE_OP 0x08000
-#define BRANCH_OP 0x10000
-#define BARRIER_OP 0x20000
+// the following are operations the timing model can see
+
+enum uarch_op_t {
+ NO_OP=-1,
+ ALU_OP=1,
+ SFU_OP,
+ ALU_SFU_OP,
+ LOAD_OP,
+ STORE_OP,
+ BRANCH_OP,
+ BARRIER_OP,
+ MEMORY_BARRIER_OP
+};
+typedef enum uarch_op_t op_type;
enum _memory_space_t {
undefined_space=0,
@@ -45,11 +35,63 @@ enum _memory_space_t {
tex_space,
surf_space,
global_space,
- generic_space
+ generic_space,
+ instruction_space
+};
+
+enum _memory_op_t {
+ no_memory_op = 0,
+ memory_load,
+ memory_store
};
#ifdef __cplusplus
+#include <list>
+
+#if !defined(__VECTOR_TYPES_H__)
+struct dim3 {
+ unsigned int x, y, z;
+};
+#endif
+
+class core_t {
+public:
+ virtual ~core_t() {}
+ virtual void set_at_barrier( unsigned cta_id, unsigned warp_id ) = 0;
+ virtual void warp_exit( unsigned warp_id ) = 0;
+ virtual bool warp_waiting_at_barrier( unsigned warp_id ) const = 0;
+ virtual bool warp_waiting_for_atomics( unsigned warp_id ) const = 0;
+ virtual class gpgpu_sim *get_gpu() = 0;
+};
+
+struct gpgpu_ptx_sim_kernel_info
+{
+ // Holds properties of the kernel (Kernel's resource use).
+ // These will be set to zero if a ptxinfo file is not present.
+ int lmem;
+ int smem;
+ int cmem;
+ int regs;
+ unsigned ptx_version;
+ unsigned sm_target;
+};
+
+struct gpgpu_ptx_sim_arg {
+ gpgpu_ptx_sim_arg() { m_start=NULL; }
+ gpgpu_ptx_sim_arg(const void *arg, size_t size, size_t offset)
+ {
+ m_start=arg;
+ m_nbytes=size;
+ m_offset=offset;
+ }
+ const void *m_start;
+ size_t m_nbytes;
+ size_t m_offset;
+};
+
+typedef std::list<gpgpu_ptx_sim_arg> gpgpu_ptx_sim_arg_list_t;
+
class memory_space_t {
public:
memory_space_t() { m_type = undefined_space; m_bank=0; }
@@ -74,6 +116,82 @@ private:
unsigned m_bank; // n in ".const[n]"; note .const == .const[0] (see PTX 2.1 manual, sec. 5.1.3)
};
-#endif
-#endif
+#define MAX_REG_OPERANDS 8
+
+struct dram_callback_t {
+ void (*function)(void* pI, void* gOldGThread);
+ void* instruction;
+ void* thread;
+};
+
+class inst_t {
+public:
+ inst_t()
+ {
+ m_decoded=false;
+ 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; }
+ virtual void print_insn( FILE *fp ) const
+ {
+ 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
+
+ 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 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() {}
+};
+
+
+const struct gpgpu_ptx_sim_kernel_info * get_kernel_info(const char *kernel_key);
+size_t get_kernel_code_size( class function_info *entry );
+
+#endif // #ifdef __cplusplus
+#endif // #ifndef ABSTRACT_HARDWARE_MODEL_INCLUDED
diff --git a/src/cuda-sim/cuda-math.h b/src/cuda-sim/cuda-math.h
index 5abf4f3..367563f 100644
--- a/src/cuda-sim/cuda-math.h
+++ b/src/cuda-sim/cuda-math.h
@@ -47,6 +47,7 @@ namespace cuda_math {
#define __attribute__(a) // to remove warnings inside math_functions.h
#undef INT_MAX
+#if CUDART_VERSION < 3000
// DEVICE_BUILTIN
struct int4 {
int x, y, z, w;
@@ -70,18 +71,245 @@ namespace cuda_math {
extern float rsqrtf(float); // CUDA 2.3 beta
-#if CUDART_VERSION < 3000
#define CUDA_FLOAT_MATH_FUNCTIONS
#include <device_types.h>
#define __CUDA_INTERNAL_COMPILATION__
#include <math_functions.h>
#undef __CUDA_INTERNAL_COMPILATION__
#undef __attribute__
+
+// float to integer conversion
+int float2int(float a, enum cudaRoundMode mode)
+{
+ return __internal_float2uint(a, mode);
+}
+
+// float to unsigned integer conversion
+unsigned int float2uint(float a, enum cudaRoundMode mode)
+{
+ return __internal_float2uint(a, mode);
+}
+
+float __ll2float_rz(long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TOWARDZERO);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ll2float_ru(long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_UPWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ll2float_rd(long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_DOWNWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+
#else
+
#define CUDA_FLOAT_MATH_FUNCTIONS
-#include "/home/taamodt/nvcuda/2.3/cuda/include/device_types.h"
+#define __CUDACC__
+
+// implementing int to float intrinsics with different rounding modes
+#include <device_types.h>
+#include <fenv.h>
+
+// 32-bit integer to float
+float __int2float_rn(int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TONEAREST);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __int2float_rz(int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TOWARDZERO);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __int2float_ru(int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_UPWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __int2float_rd(int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_DOWNWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+
+// 32-bit unsigned integer to float
+float __uint2float_rn(unsigned int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TONEAREST);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __uint2float_rz(unsigned int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TOWARDZERO);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __uint2float_ru(unsigned int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_UPWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __uint2float_rd(unsigned int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_DOWNWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+
+// 64-bit integer to float
+float __ll2float_rn(long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TONEAREST);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ll2float_rz(long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TOWARDZERO);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ll2float_ru(long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_UPWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ll2float_rd(long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_DOWNWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+
+// 64-bit unsigned integer to float
+float __ull2float_rn(unsigned long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TONEAREST);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ull2float_rz(unsigned long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_TOWARDZERO);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ull2float_ru(unsigned long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_UPWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+float __ull2float_rd(unsigned long long int a) {
+ int orig_rnd_mode = fegetround();
+ fesetround(FE_DOWNWARD);
+ float b = a;
+ fesetround(orig_rnd_mode);
+ return b;
+}
+
+// float to integer conversion
+int float2int(float a, enum cudaRoundMode mode)
+{
+ int tmp;
+ switch (mode) {
+ case cuda_math::cudaRoundZero: tmp = truncf(a); break;
+ case cuda_math::cudaRoundNearest: tmp = nearbyintf(a); break;
+ case cuda_math::cudaRoundMinInf: tmp = floorf(a); break;
+ case cuda_math::cudaRoundPosInf: tmp = ceilf(a); break;
+ default: abort();
+ }
+ return tmp;
+}
+
+int __internal_float2int(float a, enum cudaRoundMode mode)
+{
+ return float2int(a, mode);
+}
+
+// float to unsigned integer conversion
+unsigned int float2uint(float a, enum cudaRoundMode mode)
+{
+ unsigned int tmp;
+ switch (mode) {
+ case cuda_math::cudaRoundZero: tmp = truncf(a); break;
+ case cuda_math::cudaRoundNearest: tmp = nearbyintf(a); break;
+ case cuda_math::cudaRoundMinInf: tmp = floorf(a); break;
+ case cuda_math::cudaRoundPosInf: tmp = ceilf(a); break;
+ default: abort();
+ }
+ return tmp;
+}
+
+unsigned int __internal_float2uint(float a, enum cudaRoundMode mode)
+{
+ return float2uint(a, mode);
+}
+
+// intrinsic for division
+float fdividef(float a, float b)
+{
+ return (a / b);
+}
+
+float __internal_accurate_fdividef(float a, float b)
+{
+ return fdividef(a, b);
+}
+
+// intrinsic for saturate (clamp values beyond 0 and 1)
+float __saturatef(float a)
+{
+ float b;
+ if (isnan(a)) b = 0.0f;
+ else if (a >= 1.0f) b = 1.0f;
+ else if (a <= 0.0f) b = 0.0f;
+ else b = a;
+ return b;
+}
+
+// intrinsic for power
+float __powf(float a, float b)
+{
+ return powf(a, b);
+}
+
+#undef __CUDACC__
#define __CUDA_INTERNAL_COMPILATION__
-#include "/home/taamodt/nvcuda/2.3/cuda/include/math_functions.h"
+#include <math_functions.h>
#undef __CUDA_INTERNAL_COMPILATION__
#undef __attribute__
#endif
diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc
index 0a6ccd6..de4445a 100644
--- a/src/cuda-sim/cuda-sim.cc
+++ b/src/cuda-sim/cuda-sim.cc
@@ -99,7 +99,6 @@ std::map<const struct textureReference*,const struct cudaArray*> TextureToArrayM
std::map<const struct textureReference*, const struct textureInfo*> TextureToInfoMap;
std::map<std::string, const struct textureReference*> NameToTextureMap;
unsigned int g_texcache_linesize;
-int gpgpu_option_spread_blocks_across_cores = 0;
unsigned gpgpu_param_num_shaders = 0;
void gpgpu_ptx_sim_bindNameToTexture(const char* name, const struct textureReference* texref)
@@ -208,10 +207,12 @@ int gpgpu_ptx_sim_sizeofTexture(const char* name)
return array->size;
}
-unsigned g_assemble_code_next_pc=1;
+unsigned g_assemble_code_next_pc=0;
std::map<unsigned,function_info*> g_pc_to_finfo;
std::vector<ptx_instruction*> function_info::s_g_pc_to_insn;
+#define MAX_INST_SIZE 8 /*bytes*/
+
void function_info::ptx_assemble()
{
if( m_assembled ) {
@@ -220,16 +221,22 @@ void function_info::ptx_assemble()
// get the instructions into instruction memory...
unsigned num_inst = m_instructions.size();
- m_instr_mem = new ptx_instruction*[ num_inst ];
- m_instr_mem_size = num_inst;
+ m_instr_mem_size = MAX_INST_SIZE*(num_inst+1);
+ m_instr_mem = new ptx_instruction*[ m_instr_mem_size ];
printf("GPGPU-Sim PTX: instruction assembly for function \'%s\'... ", m_name.c_str() );
fflush(stdout);
std::list<ptx_instruction*>::iterator i;
- addr_t n=0; // offset in m_instr_mem
+
addr_t PC = g_assemble_code_next_pc; // globally unique address (across functions)
+ // start function on an aligned address
+ for( unsigned i=0; i < (PC%MAX_INST_SIZE); i++ )
+ s_g_pc_to_insn.push_back((ptx_instruction*)NULL);
+ PC += PC%MAX_INST_SIZE;
m_start_PC = PC;
- s_g_pc_to_insn.reserve(s_g_pc_to_insn.size() + m_instructions.size());
+
+ addr_t n=0; // offset in m_instr_mem
+ s_g_pc_to_insn.reserve(s_g_pc_to_insn.size() + MAX_INST_SIZE*m_instructions.size());
for ( i=m_instructions.begin(); i != m_instructions.end(); i++ ) {
ptx_instruction *pI = *i;
if ( pI->is_label() ) {
@@ -239,17 +246,22 @@ void function_info::ptx_assemble()
g_pc_to_finfo[PC] = this;
m_instr_mem[n] = pI;
s_g_pc_to_insn.push_back(pI);
- assert(pI == s_g_pc_to_insn[PC - 1]);
+ assert(pI == s_g_pc_to_insn[PC]);
pI->set_m_instr_mem_index(n);
pI->set_PC(PC);
- n++;
- PC++;
+ assert( pI->inst_size() <= MAX_INST_SIZE );
+ for( unsigned i=1; i < pI->inst_size(); i++ ) {
+ s_g_pc_to_insn.push_back((ptx_instruction*)NULL);
+ m_instr_mem[n+i]=NULL;
+ }
+ n += pI->inst_size();
+ PC += pI->inst_size();
}
}
g_assemble_code_next_pc=PC;
- for ( unsigned ii=0; ii < n; ii++ ) { // handle branch instructions
+ for ( unsigned ii=0; ii < n; ii += m_instr_mem[ii]->inst_size() ) { // handle branch instructions
ptx_instruction *pI = m_instr_mem[ii];
- if ( pI->get_opcode() == BRA_OP || pI->get_opcode() == BREAKADDR_OP ) {
+ if ( pI->get_opcode() == BRA_OP || pI->get_opcode() == BREAKADDR_OP || pI->get_opcode() == CALLP_OP) {
operand_info &target = pI->dst(); //get operand, e.g. target name
if ( labels.find(target.name()) == labels.end() ) {
printf("GPGPU-Sim PTX: Loader error (%s:%u): Branch label \"%s\" does not appear in assembly code.",
@@ -262,6 +274,11 @@ void function_info::ptx_assemble()
target.set_type(label_t);
}
}
+ for ( unsigned ii=0; ii < n; ii += m_instr_mem[ii]->inst_size() ) { // handle branch instructions
+ ptx_instruction *pI = m_instr_mem[ii];
+ pI->pre_decode();
+ }
+
printf(" done.\n");
fflush(stdout);
@@ -328,12 +345,12 @@ bool isspace_shared( unsigned smid, addr_t addr )
bool isspace_global( addr_t addr )
{
- return (addr > GLOBAL_HEAP_START) || (addr < STATIC_ALLOC_LIMIT);
+ return (addr >= GLOBAL_HEAP_START) || (addr < STATIC_ALLOC_LIMIT);
}
memory_space_t whichspace( addr_t addr )
{
- if( (addr > GLOBAL_HEAP_START) || (addr < STATIC_ALLOC_LIMIT) ) {
+ if( (addr >= GLOBAL_HEAP_START) || (addr < STATIC_ALLOC_LIMIT) ) {
return global_space;
} else if( addr > SHARED_GENERIC_START ) {
return shared_space;
@@ -446,14 +463,6 @@ void gpgpu_ptx_sim_memset( size_t dst_start_addr, int c, size_t count )
fflush(stdout);
}
-int ptx_thread_done( void *thd )
-{
- ptx_thread_info *the_thread = (ptx_thread_info *) thd;
- int result = 0;
- result = (the_thread==NULL) || the_thread->is_done();
- return result;
-}
-
const char * ptx_get_fname( unsigned PC )
{
static const char *null_ptr = "<null finfo ptr>";
@@ -471,14 +480,6 @@ unsigned ptx_thread_donecycle( void *thr )
return the_thread->donecycle();
}
-int ptx_thread_get_next_pc( void *thd )
-{
- ptx_thread_info *the_thread = (ptx_thread_info *) thd;
- if ( the_thread == NULL )
- return -1;
- 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)
-}
-
void* ptx_thread_get_next_finfo( void *thd )
{
ptx_thread_info *the_thread = (ptx_thread_info *) thd;
@@ -531,7 +532,7 @@ void ptx_print_insn( address_type pc, FILE *fp )
{
std::map<unsigned,function_info*>::iterator f = g_pc_to_finfo.find(pc);
if( f == g_pc_to_finfo.end() ) {
- fprintf(fp,"<no instruction at address 0x%x (%u)>", pc, pc );
+ fprintf(fp,"<no instruction at address 0x%x>", pc );
return;
}
function_info *finfo = f->second;
@@ -539,108 +540,118 @@ void ptx_print_insn( address_type pc, FILE *fp )
finfo->print_insn(pc,fp);
}
-static void get_opcode_info( const ptx_instruction *pI, unsigned opcode, unsigned *cycles, unsigned *op_type )
+static void get_opcode_info( const ptx_instruction *pI, unsigned opcode, unsigned *cycles, op_type *op )
{
- *op_type = ALU_OP;
+ *op = ALU_OP;
*cycles = 1;
if ( opcode == LD_OP ) {
- *op_type = LOAD_OP;
+ *op = LOAD_OP;
} else if ( opcode == ST_OP ) {
- *op_type = STORE_OP;
+ *op = STORE_OP;
} else if ( opcode == BRA_OP ) {
- *op_type = BRANCH_OP;
+ *op = BRANCH_OP;
} else if ( opcode == BREAKADDR_OP ) {
- *op_type = BRANCH_OP;
+ *op = BRANCH_OP;
} else if ( opcode == TEX_OP ) {
- *op_type = LOAD_OP;
+ *op = LOAD_OP;
} else if ( opcode == ATOM_OP ) {
- *op_type = LOAD_OP; // make atomics behave more like a load.
+ *op = LOAD_OP; // timing model treats this like load for now
} else if ( opcode == BAR_OP ) {
- *op_type = BARRIER_OP;
- }
+ *op = BARRIER_OP;
+ } else if ( opcode == MEMBAR_OP )
+ *op = MEMORY_BARRIER_OP;
// Floating point instructions
- if( opcode == RCP_OP || opcode == LG2_OP || opcode == RSQRT_OP ) {
- *cycles = 4;
- *op_type = SFU_OP;
+ if( opcode == RCP_OP ) {
+ *cycles = 2;
+ *op = SFU_OP;
+ } else if ( opcode == LG2_OP || opcode == RSQRT_OP ) {
+ *cycles = 4;
+ *op = SFU_OP;
} else if( opcode == SQRT_OP || opcode == SIN_OP || opcode == COS_OP || opcode == EX2_OP ) {
*cycles = 4;
- *op_type = SFU_OP;
+ *op = SFU_OP;
} else if( opcode == DIV_OP ) {
// Floating point only
if( pI->get_type() == F32_TYPE || pI->get_type() == F64_TYPE ) {
- *cycles = 8;
- *op_type = SFU_OP;
+ *cycles = 4;
+ *op = SFU_OP;
}
}
// Integer instructions
if( opcode == MUL_OP ) {
if( pI->get_type() == B32_TYPE || pI->get_type() == U32_TYPE || pI->get_type() == S32_TYPE ) {
// 32-bit integer instruction
- *cycles = 4;
- *op_type = SFU_OP;
+ *cycles = 5;
+ *op = SFU_OP;
}
+ if( pI->get_type() == F32_TYPE || pI->get_type() == F64_TYPE )
+ *op = ALU_SFU_OP;
}
+ if( opcode == MAD_OP ) {
+ if( pI->get_type() == B32_TYPE || pI->get_type() == U32_TYPE || pI->get_type() == S32_TYPE ) {
+ // 32-bit integer instruction
+ *cycles = 6;
+ *op = SFU_OP;
+ }
+ }
+}
+
+void ptx_thread_info::ptx_fetch_inst( inst_t &inst ) const
+{
+ addr_t pc = get_pc();
+ const ptx_instruction *pI = m_func_info->get_instruction(pc);
+ inst = (const inst_t&)*pI;
+ assert( inst.valid() );
}
-void function_info::ptx_decode_inst( ptx_thread_info *thread,
- unsigned *op_type,
- int *i1, int *i2, int *i3, int *i4,
- int *o1, int *o2, int *o3, int *o4,
- int *vectorin,
- int *vectorout,
- int *arch_reg,
- int *pred,
- int *ar1, int *ar2 )
+void ptx_instruction::pre_decode()
{
- addr_t pc = thread->get_pc();
- unsigned index = pc - m_start_PC;
- assert( index < m_instr_mem_size );
- ptx_instruction *pI = m_instr_mem[index]; //get instruction from m_instr_mem[PC]
+ pc = m_PC;
+ isize = m_inst_size;
+ for( unsigned i=0; i<4; i++) {
+ out[i] = 0;
+ in[i] = 0;
+ }
+ is_vectorin = 0;
+ is_vectorout = 0;
+ std::fill_n(arch_reg, MAX_REG_OPERANDS, -1);
+ pred = 0;
+ ar1 = 0;
+ ar2 = 0;
bool has_dst = false ;
- int opcode = pI->get_opcode(); //determine the opcode
+ int opcode = get_opcode(); //determine the opcode
- switch ( pI->get_opcode() ) {
+ switch ( get_opcode() ) {
#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: has_dst = (DST!=0); break;
#include "opcodes.def"
#undef OP_DEF
default:
- printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() );
+ printf( "Execution error: Invalid opcode (0x%x)\n", get_opcode() );
break;
}
- unsigned cycles;
- get_opcode_info(pI,opcode,&cycles,op_type);
-
- // Quick fix for memory operands in ALU instructions
- if( pI->has_memory_read() )
- *op_type = LOAD_OP;
- else if( pI->has_memory_write() )
- *op_type = STORE_OP;
-
- if( pI->has_memory_read() && pI->has_memory_write() ) {
- printf("Instruction has both a memory read and memory write - not supported by timing simulator.");
- assert(0);
- }
+ get_opcode_info(this,opcode,&cycles,&op);
// Get register operands
int n=0,m=0;
- ptx_instruction::const_iterator op=pI->op_iter_begin();
- for ( ; op != pI->op_iter_end(); op++, n++ ) { //process operands
+ ptx_instruction::const_iterator opr=op_iter_begin();
+ for ( ; opr != op_iter_end(); opr++, n++ ) { //process operands
- const operand_info &o = *op;
+ const operand_info &o = *opr;
if ( has_dst && n==0 ) {
if ( o.is_reg() ) { //but is destination an actual register? (seems like it fails if it's a vector)
- *o1 = o.reg_num();
+ out[0] = o.reg_num();
arch_reg[0] = o.arch_reg_num();
} else if ( o.is_vector() ) { //but is destination an actual register? (seems like it fails if it's a vector)
- *vectorin = 1;
- *o1 = o.reg1_num();
- *o2 = o.reg2_num();
- *o3 = o.reg3_num();
- *o4 = o.reg4_num();
- for (int i = 0; i < 4; i++)
+ is_vectorin = 1;
+ unsigned num_elem = o.get_vect_nelem();
+ if( num_elem >= 1 ) out[0] = o.reg1_num();
+ if( num_elem >= 2 ) out[1] = o.reg2_num();
+ if( num_elem >= 3 ) out[2] = o.reg3_num();
+ if( num_elem >= 4 ) out[3] = o.reg4_num();
+ for (int i = 0; i < num_elem; i++)
arch_reg[i] = o.arch_reg_num(i);
}
} else {
@@ -648,21 +659,21 @@ void function_info::ptx_decode_inst( ptx_thread_info *thread,
int reg_num = o.reg_num();
arch_reg[m + 4] = o.arch_reg_num();
switch ( m ) {
- case 0: *i1 = reg_num; break;
- case 1: *i2 = reg_num; break;
- case 2: *i3 = reg_num; break;
- default:
- break;
+ case 0: in[0] = reg_num; break;
+ case 1: in[1] = reg_num; break;
+ case 2: in[2] = reg_num; break;
+ default: break;
}
m++;
} else if ( o.is_vector() ) {
assert(m == 0); //only support 1 vector operand (for textures) right now
- *vectorout = 1;
- *i1 = o.reg1_num();
- *i2 = o.reg2_num();
- *i3 = o.reg3_num();
- *i4 = o.reg4_num();
- for (int i = 0; i < 4; i++)
+ is_vectorout = 1;
+ unsigned num_elem = o.get_vect_nelem();
+ if( num_elem >= 1 ) in[0] = o.reg1_num();
+ if( num_elem >= 2 ) in[1] = o.reg2_num();
+ if( num_elem >= 3 ) in[2] = o.reg3_num();
+ if( num_elem >= 4 ) in[3] = o.reg4_num();
+ for (int i = 0; i < num_elem; i++)
arch_reg[i + 4] = o.arch_reg_num(i);
m+=4;
}
@@ -670,64 +681,34 @@ void function_info::ptx_decode_inst( ptx_thread_info *thread,
}
// Get predicate
- if(pI->has_pred()) {
- const operand_info &p = pI->get_pred();
- *pred = p.reg_num();
- }
-
- // Get address registers inside memory operands.
- // Assuming only one memory operand per instruction,
- // and maximum of two address registers for one memory operand.
- if( pI->has_memory_read() || pI->has_memory_write() ) {
- ptx_instruction::const_iterator op=pI->op_iter_begin();
- for ( ; op != pI->op_iter_end(); op++, n++ ) { //process operands
- const operand_info &o = *op;
-
- // memory operand with addressing (ex. s[0x4] or g[$r1])
- if(o.is_memory_operand2()) {
- // memory operand with one address register (ex. g[$r1] or s[$r2+0x4])
- if(o.get_double_operand_type() == 0 && o.is_memory_operand()){
- *ar1 = o.reg_num();
- }
- // memory operand with two address register (ex. s[$r1+$r1] or g[$r1+=$r2])
- else if(o.get_double_operand_type() == 1 || o.get_double_operand_type() == 2) {
- *ar1 = o.reg1_num();
- *ar2 = o.reg2_num();
- }
- }
- }
- }
-
- // Get predicate
- if(pI->has_pred()) {
- const operand_info &p = pI->get_pred();
- *pred = p.reg_num();
+ if(has_pred()) {
+ const operand_info &p = get_pred();
+ pred = p.reg_num();
}
// Get address registers inside memory operands.
// Assuming only one memory operand per instruction,
// and maximum of two address registers for one memory operand.
- if( pI->has_memory_read() || pI->has_memory_write() ) {
- ptx_instruction::const_iterator op=pI->op_iter_begin();
- for ( ; op != pI->op_iter_end(); op++, n++ ) { //process operands
+ if( has_memory_read() || has_memory_write() ) {
+ ptx_instruction::const_iterator op=op_iter_begin();
+ for ( ; op != op_iter_end(); op++, n++ ) { //process operands
const operand_info &o = *op;
// memory operand with addressing (ex. s[0x4] or g[$r1])
if(o.is_memory_operand2()) {
// memory operand with one address register (ex. g[$r1] or s[$r2+0x4])
if(o.get_double_operand_type() == 0 && o.is_memory_operand()){
- const symbol *base_addr = o.get_symbol();
- if( base_addr->is_reg() )
- *ar1 = base_addr->reg_num();
+ ar1 = o.reg_num();
}
// memory operand with two address register (ex. s[$r1+$r1] or g[$r1+=$r2])
else if(o.get_double_operand_type() == 1 || o.get_double_operand_type() == 2) {
- *ar1 = o.reg1_num();
- *ar2 = o.reg2_num();
+ ar1 = o.reg1_num();
+ ar2 = o.reg2_num();
}
}
}
}
+ m_decoded=true;
}
void function_info::add_param_name_type_size( unsigned index, std::string name, int type, size_t size )
@@ -855,7 +836,7 @@ void function_info::param_to_shared( memory_space *shared_mem, symbol_table *sym
type_info_key::type_decode(xtype,size,tmp);
// Write to shared memory - offset + 0x10
- shared_mem->write(offset+0x10,size/8,&value,NULL,NULL);
+ shared_mem->write(offset+0x10,size/8,value.pdata,NULL,NULL);
}
}
@@ -923,49 +904,45 @@ unsigned datatype2size( unsigned data_type )
unsigned g_warp_active_mask;
-void function_info::ptx_exec_inst( ptx_thread_info *thread,
- addr_t *addr,
- memory_space_t *space,
- unsigned *data_size,
- unsigned *cycles,
- dram_callback_t* callback,
- unsigned warp_active_mask )
+void ptx_thread_info::ptx_exec_inst( inst_t &inst )
{
+ inst.memory_op = no_memory_op;
bool skip = false;
int op_classification = 0;
- addr_t pc = thread->next_instr();
- unsigned index = pc - m_start_PC;
- assert( index < m_instr_mem_size );
- ptx_instruction *pI = m_instr_mem[index];
+ addr_t pc = next_instr();
+ assert( pc == inst.pc ); // make sure timing model and functional model are in sync
+ const ptx_instruction *pI = m_func_info->get_instruction(pc);
+ set_npc( pc + pI->inst_size() );
+
try {
- thread->clearRPC();
- thread->m_last_set_operand_value.u64 = 0;
+ clearRPC();
+ m_last_set_operand_value.u64 = 0;
- if(thread->is_done())
+ if(is_done())
{
printf("attempted to execute instruction on a thread that is already done.\n");
assert(0);
}
- if ( g_debug_execution >= 6 ) {
- if ( (g_debug_thread_uid==0) || (thread->get_uid() == (unsigned)g_debug_thread_uid) ) {
- thread->clear_modifiedregs();
- thread->enable_debug_trace();
+ if ( g_debug_execution >= 6 || g_ptx_inst_debug_to_file) {
+ if ( (g_debug_thread_uid==0) || (get_uid() == (unsigned)g_debug_thread_uid) ) {
+ clear_modifiedregs();
+ enable_debug_trace();
}
}
if( pI->has_pred() ) {
const operand_info &pred = pI->get_pred();
- ptx_reg_t pred_value = thread->get_operand_value(pred, pred, PRED_TYPE, thread, 0);
+ ptx_reg_t pred_value = get_operand_value(pred, pred, PRED_TYPE, this, 0);
if(pI->get_pred_mod() == -1) {
skip = (pred_value.pred & 0x0001) ^ pI->get_pred_neg(); //ptxplus inverts the zero flag
} else {
skip = !pred_lookup(pI->get_pred_mod(), pred_value.pred & 0x000F);
}
}
- g_warp_active_mask = warp_active_mask;
+ 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,thread); op_classification = CLASSIFICATION; break;
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,this); op_classification = CLASSIFICATION; break;
#include "opcodes.def"
#undef OP_DEF
@@ -976,110 +953,108 @@ void function_info::ptx_exec_inst( ptx_thread_info *thread,
// Run exit instruction if exit option included
if(pI->is_exit())
- exit_impl(pI,thread);
+ exit_impl(pI,this);
}
// Output instruction information to file and stdout
if( g_ptx_inst_debug_to_file != 0 &&
- (g_ptx_inst_debug_thread_uid == 0 || g_ptx_inst_debug_thread_uid == thread->get_uid()) ) {
- dim3 ctaid = thread->get_ctaid();
- dim3 tid = thread->get_tid();
+ (g_ptx_inst_debug_thread_uid == 0 || g_ptx_inst_debug_thread_uid == get_uid()) ) {
+ dim3 ctaid = get_ctaid();
+ dim3 tid = get_tid();
fprintf(ptx_inst_debug_file,
"[thd=%u] : (%s:%u - %s)\n",
- thread->get_uid(),
+ get_uid(),
pI->source_file(), pI->source_line(), pI->get_source() );
//fprintf(ptx_inst_debug_file, "has memory read=%d, has memory write=%d\n", pI->has_memory_read(), pI->has_memory_write());
fflush(ptx_inst_debug_file);
}
- if ( ptx_debug_exec_dump_cond<5>(thread->get_uid(), pc) ) {
- dim3 ctaid = thread->get_ctaid();
- dim3 tid = thread->get_tid();
- printf("%u [cyc=%u][thd=%u][i=%u] : ctaid=(%u,%u,%u) tid=(%u,%u,%u) icount=%u [pc=%u] (%s:%u - %s) [0x%llx]\n",
+ if ( ptx_debug_exec_dump_cond<5>(get_uid(), pc) ) {
+ dim3 ctaid = get_ctaid();
+ dim3 tid = get_tid();
+ printf("%u [thd=%u][i=%u] : ctaid=(%u,%u,%u) tid=(%u,%u,%u) icount=%u [pc=%u] (%s:%u - %s) [0x%llx]\n",
g_ptx_sim_num_insn,
- (unsigned)gpu_sim_cycle,
- thread->get_uid(),
+ get_uid(),
pI->uid(), ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z,
- thread->get_icount(),
+ get_icount(),
pc, pI->source_file(), pI->source_line(), pI->get_source(),
- thread->m_last_set_operand_value.u64 );
+ m_last_set_operand_value.u64 );
fflush(stdout);
}
addr_t insn_memaddr = 0xFEEBDAED;
memory_space_t insn_space = undefined_space;
+ _memory_op_t insn_memory_op = no_memory_op;
unsigned insn_data_size = 0;
if ( (pI->has_memory_read() || pI->has_memory_write()) ) {
- insn_memaddr = thread->last_eaddr();
- insn_space = thread->last_space();
+ insn_memaddr = last_eaddr();
+ insn_space = last_space();
unsigned to_type = pI->get_type();
insn_data_size = datatype2size(to_type);
+ insn_memory_op = pI->has_memory_read() ? memory_load : memory_store;
}
if ( pI->get_opcode() == ATOM_OP ) {
- insn_memaddr = thread->last_eaddr();
- insn_space = thread->last_space();
- callback->function = thread->last_callback().function;
- callback->instruction = thread->last_callback().instruction;
- callback->thread = thread;
+ insn_memaddr = last_eaddr();
+ insn_space = last_space();
+ inst.callback.function = last_callback().function;
+ inst.callback.instruction = last_callback().instruction;
+ inst.callback.thread = this;
unsigned to_type = pI->get_type();
insn_data_size = datatype2size(to_type);
} else {
// make sure that the callback isn't set
- callback->function = NULL;
- callback->instruction = NULL;
+ inst.callback.function = NULL;
+ inst.callback.instruction = NULL;
+ inst.callback.thread = NULL;
}
- // Set number of cycles for this instruction
- int opcode = pI->get_opcode(); //determine the opcode
- unsigned op_type;
- get_opcode_info(pI,opcode,cycles,&op_type);
-
if (pI->get_opcode() == TEX_OP) {
- *addr = thread->last_eaddr();
- *space = thread->last_space();
+ inst.memreqaddr = last_eaddr();
+ inst.space = last_space();
unsigned to_type = pI->get_type();
switch ( to_type ) {
case B8_TYPE:
case S8_TYPE:
case U8_TYPE:
- *data_size = 1; break;
+ inst.data_size = 1; break;
case B16_TYPE:
case S16_TYPE:
case U16_TYPE:
case F16_TYPE:
- *data_size = 2; break;
+ inst.data_size = 2; break;
case B32_TYPE:
case S32_TYPE:
case U32_TYPE:
case F32_TYPE:
- *data_size = 4; break;
+ inst.data_size = 4; break;
case B64_TYPE:
case S64_TYPE:
case U64_TYPE:
case F64_TYPE:
- *data_size = 8; break;
+ inst.data_size = 8; break;
default: assert(0); break;
}
}
// Output register information to file and stdout
if( g_ptx_inst_debug_to_file != 0 &&
- (g_ptx_inst_debug_thread_uid == 0 || g_ptx_inst_debug_thread_uid == thread->get_uid()) ) {
- thread->dump_modifiedregs(ptx_inst_debug_file);
+ (g_ptx_inst_debug_thread_uid == 0 || g_ptx_inst_debug_thread_uid == get_uid()) ) {
+ dump_modifiedregs(ptx_inst_debug_file);
+ dump_regs(ptx_inst_debug_file);
}
if ( g_debug_execution >= 6 ) {
- if ( ptx_debug_exec_dump_cond<6>(thread->get_uid(), pc) )
- thread->dump_modifiedregs(stdout);
+ if ( ptx_debug_exec_dump_cond<6>(get_uid(), pc) )
+ dump_modifiedregs(stdout);
}
if ( g_debug_execution >= 10 ) {
- if ( ptx_debug_exec_dump_cond<10>(thread->get_uid(), pc) )
- thread->dump_regs(stdout);
+ if ( ptx_debug_exec_dump_cond<10>(get_uid(), pc) )
+ dump_regs(stdout);
}
- thread->update_pc();
+ update_pc( pI->inst_size() );
g_ptx_sim_num_insn++;
ptx_file_line_stats_add_exec_count(pI);
if ( gpgpu_ptx_instruction_classification ) {
@@ -1103,17 +1078,24 @@ void function_info::ptx_exec_inst( ptx_thread_info *thread,
StatAddSample( g_inst_op_classification_stat[g_ptx_kernel_count], (int) pI->get_opcode() );
}
if ( (g_ptx_sim_num_insn % 100000) == 0 ) {
- dim3 ctaid = thread->get_ctaid();
- dim3 tid = thread->get_tid();
+ dim3 ctaid = get_ctaid();
+ dim3 tid = get_tid();
printf("GPGPU-Sim PTX: %u instructions simulated : ctaid=(%u,%u,%u) tid=(%u,%u,%u)\n",
g_ptx_sim_num_insn, ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z );
fflush(stdout);
}
// "Return values"
- *space = insn_space;
- *addr = insn_memaddr;
- *data_size = insn_data_size;
+ if(!skip) {
+ inst.space = insn_space;
+ inst.memreqaddr = 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;
+ }
} catch ( int x ) {
printf("GPGPU-Sim PTX: ERROR (%d) executing intruction (%s:%u)\n", x, pI->source_file(), pI->source_line() );
@@ -1122,10 +1104,6 @@ void function_info::ptx_exec_inst( ptx_thread_info *thread,
}
}
-unsigned g_gx, g_gy, g_gz;
-
-dim3 g_cudaGridDim, g_cudaBlockDim;
-
unsigned g_cta_launch_sid;
std::list<ptx_thread_info *> g_active_threads;
std::map<unsigned,unsigned> g_sm_idx_offset_next;
@@ -1134,45 +1112,39 @@ std::map<unsigned,memory_space*> g_shared_memory_lookup;
std::map<unsigned,ptx_cta_info*> g_ptx_cta_lookup;
std::map<unsigned,std::map<unsigned,memory_space*> > g_local_memory_lookup;
-// return number of blocks in grid
-unsigned ptx_sim_grid_size()
-{
- return g_cudaGridDim.x * g_cudaGridDim.y * g_cudaGridDim.z;
-}
-
-void set_option_gpgpu_spread_blocks_across_cores(int option)
-{
- gpgpu_option_spread_blocks_across_cores = option;
-}
-
void set_param_gpgpu_num_shaders(int num_shaders)
{
gpgpu_param_num_shaders = num_shaders;
}
-unsigned ptx_sim_cta_size()
+const struct gpgpu_ptx_sim_kernel_info* ptx_sim_kernel_info(function_info *kernel)
{
- return g_cudaBlockDim.x * g_cudaBlockDim.y * g_cudaBlockDim.z;
-}
-
-const struct gpgpu_ptx_sim_kernel_info* ptx_sim_kernel_info() {
- return g_entrypoint_func_info->get_kernel_info();
+ return kernel->get_kernel_info();
}
-void ptx_sim_free_sm( ptx_thread_info** thread_info )
+const inst_t *ptx_fetch_inst( address_type pc )
{
+ return function_info::pc_to_instruction(pc);
}
-unsigned ptx_sim_init_thread( ptx_thread_info** thread_info,int sid,unsigned tid,unsigned threads_left,unsigned num_threads, core_t *core, unsigned hw_cta_id, unsigned hw_warp_id )
+unsigned ptx_sim_init_thread( kernel_info_t &kernel,
+ ptx_thread_info** thread_info,
+ int sid,
+ unsigned tid,
+ unsigned threads_left,
+ unsigned num_threads,
+ core_t *core,
+ unsigned hw_cta_id,
+ unsigned hw_warp_id )
{
if ( *thread_info != NULL ) {
ptx_thread_info *thd = *thread_info;
assert( thd->is_done() );
if ( g_debug_execution==-1 ) {
dim3 ctaid = thd->get_ctaid();
- dim3 tid = thd->get_tid();
+ dim3 t = thd->get_tid();
printf("GPGPU-Sim PTX simulator: thread exiting ctaid=(%u,%u,%u) tid=(%u,%u,%u) uid=%u\n",
- ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z, thd->get_uid() );
+ ctaid.x,ctaid.y,ctaid.z,t.x,t.y,t.z, thd->get_uid() );
fflush(stdout);
}
thd->m_cta_info->assert_barrier_empty();
@@ -1197,11 +1169,11 @@ unsigned ptx_sim_init_thread( ptx_thread_info** thread_info,int sid,unsigned tid
return 1;
}
- if ( g_gx >= g_cudaGridDim.x || g_gy >= g_cudaGridDim.y || g_gz >= g_cudaGridDim.z ) {
+ if ( kernel.no_more_ctas_to_run() ) {
return 0; //finished!
}
- if ( threads_left < ptx_sim_cta_size() ) {
+ if ( threads_left < kernel.threads_per_cta() ) {
return 0;
}
@@ -1214,25 +1186,12 @@ unsigned ptx_sim_init_thread( ptx_thread_info** thread_info,int sid,unsigned tid
ptx_cta_info *cta_info = NULL;
memory_space *shared_mem = NULL;
- unsigned cta_size = ptx_sim_cta_size(); //blocksize
+ unsigned cta_size = kernel.threads_per_cta();
unsigned sm_offset = g_sm_idx_offset_next[sid];
unsigned max_cta_per_sm = num_threads/cta_size; // e.g., 256 / 48 = 5
assert( max_cta_per_sm > 0 );
- unsigned sm_idx = sid*max_cta_per_sm + sm_offset;
- sm_idx = max_cta_per_sm*sid + tid/cta_size;
-
- if (!gpgpu_option_spread_blocks_across_cores) {
- // update offset...
- if ( (sm_offset + 1) >= max_cta_per_sm ) {
- sm_offset = 0;
- } else {
- sm_offset++;
- }
- g_sm_idx_offset_next[sid] = sm_offset;
- } else {
- sm_idx = (tid/cta_size)*gpgpu_param_num_shaders + sid;
- }
+ unsigned sm_idx = (tid/cta_size)*gpgpu_param_num_shaders + sid;
if ( g_shared_memory_lookup.find(sm_idx) == g_shared_memory_lookup.end() ) {
if ( g_debug_execution >= 1 ) {
@@ -1256,67 +1215,57 @@ unsigned ptx_sim_init_thread( ptx_thread_info** thread_info,int sid,unsigned tid
}
std::map<unsigned,memory_space*> &local_mem_lookup = g_local_memory_lookup[sid];
- unsigned new_tid;
- for ( unsigned tz=0; tz < g_cudaBlockDim.z; tz++ ) {
- for ( unsigned ty=0; ty < g_cudaBlockDim.y; ty++ ) {
- for ( unsigned tx=0; tx < g_cudaBlockDim.x; tx++ ) {
- new_tid = tx + g_cudaBlockDim.x*ty + g_cudaBlockDim.x*g_cudaBlockDim.y*tz;
- new_tid += tid;
- ptx_thread_info *thd = new ptx_thread_info();
-
- memory_space *local_mem = NULL;
- std::map<unsigned,memory_space*>::iterator l = local_mem_lookup.find(new_tid);
- if ( l != local_mem_lookup.end() ) {
- local_mem = l->second;
- } else {
- char buf[512];
- snprintf(buf,512,"local_%u_%u", sid, new_tid);
- local_mem = new memory_space_impl<32>(buf,32);
- local_mem_lookup[new_tid] = local_mem;
- }
- thd->set_info(g_entrypoint_func_info);
- thd->set_nctaid(g_cudaGridDim.x,g_cudaGridDim.y,g_cudaGridDim.z);
- thd->set_ntid(g_cudaBlockDim.x,g_cudaBlockDim.y,g_cudaBlockDim.z);
- thd->set_ctaid(g_gx,g_gy,g_gz);
- thd->set_tid(tx,ty,tz);
- if( g_entrypoint_func_info->get_ptx_version().extensions() )
- thd->cpy_tid_to_reg(tx,ty,tz);
- thd->set_hw_tid((unsigned)-1);
- thd->set_hw_wid((unsigned)-1);
- thd->set_hw_ctaid((unsigned)-1);
- thd->set_core(NULL);
- thd->set_hw_sid((unsigned)-1);
- thd->set_valid();
- thd->m_shared_mem = shared_mem;
- function_info *finfo = thd->func_info();
- symbol_table *st = finfo->get_symtab();
- thd->func_info()->param_to_shared(thd->m_shared_mem,st);
- thd->m_cta_info = cta_info;
- cta_info->add_thread(thd);
- thd->m_local_mem = local_mem;
- if ( g_debug_execution==-1 ) {
- printf("GPGPU-Sim PTX simulator: allocating thread ctaid=(%u,%u,%u) tid=(%u,%u,%u) @ 0x%Lx\n",
- g_gx,g_gy,g_gz,tx,ty,tz, (unsigned long long)thd );
- fflush(stdout);
- }
- g_active_threads.push_back(thd);
- }
+ while( kernel.more_threads_in_cta() ) {
+ dim3 ctaid3d = kernel.get_next_cta_id();
+ unsigned new_tid = kernel.get_next_thread_id();
+ dim3 tid3d = kernel.get_next_thread_id_3d();
+ kernel.increment_thread_id();
+ new_tid += tid;
+ ptx_thread_info *thd = new ptx_thread_info();
+
+ memory_space *local_mem = NULL;
+ std::map<unsigned,memory_space*>::iterator l = local_mem_lookup.find(new_tid);
+ if ( l != local_mem_lookup.end() ) {
+ local_mem = l->second;
+ } else {
+ char buf[512];
+ snprintf(buf,512,"local_%u_%u", sid, new_tid);
+ local_mem = new memory_space_impl<32>(buf,32);
+ local_mem_lookup[new_tid] = local_mem;
}
+ thd->set_info(kernel.entry());
+ thd->set_nctaid(kernel.get_grid_dim());
+ thd->set_ntid(kernel.get_cta_dim());
+ thd->set_ctaid(ctaid3d);
+ thd->set_tid(tid3d);
+ if( kernel.entry()->get_ptx_version().extensions() )
+ thd->cpy_tid_to_reg(tid3d);
+ thd->set_hw_tid((unsigned)-1);
+ thd->set_hw_wid((unsigned)-1);
+ thd->set_hw_ctaid((unsigned)-1);
+ thd->set_core(NULL);
+ thd->set_hw_sid((unsigned)-1);
+ thd->set_valid();
+ thd->m_shared_mem = shared_mem;
+ function_info *finfo = thd->func_info();
+ symbol_table *st = finfo->get_symtab();
+ thd->func_info()->param_to_shared(thd->m_shared_mem,st);
+ thd->m_cta_info = cta_info;
+ cta_info->add_thread(thd);
+ thd->m_local_mem = local_mem;
+ if ( g_debug_execution==-1 ) {
+ printf("GPGPU-Sim PTX simulator: allocating thread ctaid=(%u,%u,%u) tid=(%u,%u,%u) @ 0x%Lx\n",
+ ctaid3d.x,ctaid3d.y,ctaid3d.z,tid3d.x,tid3d.y,tid3d.z, (unsigned long long)thd );
+ fflush(stdout);
+ }
+ g_active_threads.push_back(thd);
}
if ( g_debug_execution==-1 ) {
printf("GPGPU-Sim PTX simulator: <-- FINISHING THREAD ALLOCATION\n");
fflush(stdout);
}
- g_gx++;
- if ( g_gx >= g_cudaGridDim.x ) {
- g_gx = 0;
- g_gy++;
- if ( g_gy >= g_cudaGridDim.y ) {
- g_gy = 0;
- g_gz++;
- }
- }
+ kernel.increment_cta_id();
g_cta_launch_sid = -1;
@@ -1336,7 +1285,7 @@ unsigned ptx_sim_init_thread( ptx_thread_info** thread_info,int sid,unsigned tid
void init_inst_classification_stat() {
char kernelname[256] ="";
-#define MAX_CLASS_KER 256
+#define MAX_CLASS_KER 1024
if (!g_inst_classification_stat) g_inst_classification_stat = (void**)calloc(MAX_CLASS_KER, sizeof(void*));
snprintf(kernelname, MAX_CLASS_KER, "Kernel %d Classification\n",g_ptx_kernel_count );
assert( g_ptx_kernel_count < MAX_CLASS_KER ) ; // a static limit on number of kernels increase it if it fails!
@@ -1350,21 +1299,12 @@ void init_inst_classification_stat() {
std::map<std::string,function_info*> *g_kernel_name_to_function_lookup=NULL;
std::map<const void*,std::string> *g_host_to_kernel_entrypoint_name_lookup=NULL;
-void gpgpu_cuda_ptx_sim_init_grid( const char *kernel_key, struct gpgpu_ptx_sim_arg* args,
- struct dim3 gridDim, struct dim3 blockDim )
+function_info *get_kernel(const char *kernel_key, std::string &kernel_func_name_mangled )
{
- g_gx=0;
- g_gy=0;
- g_gz=0;
- g_cudaGridDim = gridDim;
- g_cudaBlockDim = blockDim;
- g_sm_idx_offset_next.clear();
- g_sm_next_index = 0;
-
if ( g_host_to_kernel_entrypoint_name_lookup->find(kernel_key) ==
g_host_to_kernel_entrypoint_name_lookup->end() ) {
- printf("GPGPU-Sim PTX: ERROR ** cannot locate PTX entry point\n" );
- printf("GPGPU-Sim PTX: existing entry points: \n");
+ printf("GPGPU-Sim PTX: ERROR ** cannot locate __global__ function from hostPtr\n" );
+ printf("GPGPU-Sim PTX: registered PTX kernels: \n");
std::map<const void*,std::string>::iterator i_eptr = g_host_to_kernel_entrypoint_name_lookup->begin();
for (; i_eptr != g_host_to_kernel_entrypoint_name_lookup->end(); ++i_eptr) {
printf("GPGPU-Sim PTX: (%p,%s)\n", i_eptr->first, i_eptr->second.c_str());
@@ -1372,71 +1312,77 @@ void gpgpu_cuda_ptx_sim_init_grid( const char *kernel_key, struct gpgpu_ptx_sim_
printf("\n");
abort();
}
-
- std::string kname = (*g_host_to_kernel_entrypoint_name_lookup)[kernel_key];
- printf("GPGPU-Sim PTX: Launching kernel \'%s\' gridDim= (%u,%u,%u) blockDim = (%u,%u,%u); ntuid=%u\n",
- kname.c_str(), g_cudaGridDim.x,g_cudaGridDim.y,g_cudaGridDim.z,g_cudaBlockDim.x,g_cudaBlockDim.y,g_cudaBlockDim.z,
- g_ptx_thread_info_uid_next );
-
- if ( g_kernel_name_to_function_lookup->find(kname) ==
+ kernel_func_name_mangled = (*g_host_to_kernel_entrypoint_name_lookup)[kernel_key];
+ if ( g_kernel_name_to_function_lookup->find(kernel_func_name_mangled) ==
g_kernel_name_to_function_lookup->end() ) {
- printf("GPGPU-Sim PTX: ERROR ** function \'%s\' not found in ptx file\n", kname.c_str() );
+ printf("GPGPU-Sim PTX: ERROR ** function \'%s\' not found in ptx file\n",
+ kernel_func_name_mangled.c_str() );
abort();
}
- g_entrypoint_func_info = g_func_info = (*g_kernel_name_to_function_lookup)[kname];
+ return (*g_kernel_name_to_function_lookup)[kernel_func_name_mangled];
+}
- unsigned argcount=0;
- struct gpgpu_ptx_sim_arg *tmparg = args;
- while (tmparg) {
- tmparg = tmparg->m_next;
- argcount++;
- }
+const struct gpgpu_ptx_sim_kernel_info * get_kernel_info(const char *kernel_key)
+{
+ std::string kname;
+ function_info *finfo = get_kernel(kernel_key,kname);
+ return finfo->get_kernel_info();
+}
+
+size_t get_kernel_code_size( class function_info *entry )
+{
+ return entry->get_function_size();
+}
+kernel_info_t gpgpu_cuda_ptx_sim_init_grid( const char *kernel_key, gpgpu_ptx_sim_arg_list_t args,
+ struct dim3 gridDim, struct dim3 blockDim )
+{
+ g_sm_idx_offset_next.clear();
+ g_sm_next_index = 0;
+ std::string kname;
+ function_info *entry = get_kernel(kernel_key,kname);
+
+ printf("GPGPU-Sim PTX: Launching kernel \'%s\' gridDim= (%u,%u,%u) blockDim = (%u,%u,%u); ntuid=%u\n",
+ kname.c_str(), gridDim.x,gridDim.y,gridDim.z,blockDim.x,blockDim.y,blockDim.z,
+ g_ptx_thread_info_uid_next );
+
+
+ unsigned argcount=args.size();
unsigned argn=1;
- while (args) {
- g_func_info->add_param_data(argcount-argn,args);
- args = args->m_next;
+ for( gpgpu_ptx_sim_arg_list_t::iterator a = args.begin(); a != args.end(); a++ ) {
+ entry->add_param_data(argcount-argn,&(*a));
argn++;
}
- g_func_info->finalize(g_param_mem);
+
+ entry->finalize(g_param_mem);
g_ptx_kernel_count++;
if ( gpgpu_ptx_instruction_classification ) {
init_inst_classification_stat();
}
fflush(stdout);
+
+ return kernel_info_t(gridDim,blockDim,entry);
}
-void gpgpu_opencl_ptx_sim_init_grid(class function_info *entry,struct gpgpu_ptx_sim_arg *args, struct dim3 gridDim, struct dim3 blockDim )
+kernel_info_t gpgpu_opencl_ptx_sim_init_grid(class function_info *entry,gpgpu_ptx_sim_arg_list_t args, struct dim3 gridDim, struct dim3 blockDim )
{
- g_gx=0;
- g_gy=0;
- g_gz=0;
- g_cudaGridDim = gridDim;
- g_cudaBlockDim = blockDim;
g_sm_idx_offset_next.clear();
g_sm_next_index = 0;
- g_entrypoint_func_info = g_func_info = entry;
-
- unsigned argcount=0;
- struct gpgpu_ptx_sim_arg *tmparg = args;
- while (tmparg) {
- tmparg = tmparg->m_next;
- argcount++;
- }
-
+ unsigned argcount=args.size();
unsigned argn=1;
- while (args) {
- g_func_info->add_param_data(argcount-argn,args);
- args = args->m_next;
+ for( gpgpu_ptx_sim_arg_list_t::iterator a = args.begin(); a != args.end(); a++ ) {
+ entry->add_param_data(argcount-argn,&(*a));
argn++;
}
- g_func_info->finalize(g_param_mem);
+ entry->finalize(g_param_mem);
g_ptx_kernel_count++;
if ( gpgpu_ptx_instruction_classification ) {
init_inst_classification_stat();
}
fflush(stdout);
+
+ return kernel_info_t(gridDim,blockDim,entry);
}
const char *g_gpgpusim_version_string = "2.1.1b (beta)";
@@ -1625,7 +1571,7 @@ ptx_cta_info *g_func_cta_info = NULL;
#define MAX(a,b) (((a)>(b))?(a):(b))
-void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 blockDim, struct gpgpu_ptx_sim_arg *args)
+void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 blockDim, gpgpu_ptx_sim_arg_list_t args)
{
printf("GPGPU-Sim: Performing Functional Simulation...\n");
@@ -1634,12 +1580,11 @@ void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 bl
exit(1);
time_t end_time, elapsed_time, days, hrs, minutes, sec;
- int i1, i2, i3, i4, o1, o2, o3, o4;
- int vectorin, vectorout;
- int pred;
- int ar1, ar2;
- gpgpu_cuda_ptx_sim_init_grid(kernel_key, args,gridDim,blockDim);
+ kernel_info_t kernel = gpgpu_cuda_ptx_sim_init_grid(kernel_key, args,gridDim,blockDim);
+
+ std::string kname;
+ function_info *finfo = get_kernel(kernel_key,kname);
memory_space *shared_mem = new memory_space_impl<16*1024>("shared",4);
@@ -1647,46 +1592,40 @@ void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 bl
if ( g_func_cta_info == NULL )
g_func_cta_info = new ptx_cta_info(0);
-
- for ( unsigned gx=0; gx < gridDim.x; gx++ ) {
- for ( unsigned gy=0; gy < gridDim.y; gy++ ) {
- for ( unsigned gz=0; gz < gridDim.z; gz++ ) {
+ while( !kernel.no_more_ctas_to_run() ) {
std::list<ptx_thread_info *> active_threads;
std::list<ptx_thread_info *> blocked_threads;
+ dim3 ctaid3d = kernel.get_next_cta_id();
+ kernel.increment_cta_id();
g_func_cta_info->check_cta_thread_status_and_reset();
-
- for ( unsigned tx=0; tx < blockDim.x; tx++ ) {
- for ( unsigned ty=0; ty < blockDim.y; ty++ ) {
- for ( unsigned tz=0; tz < blockDim.z; tz++ ) {
+ while( kernel.more_threads_in_cta() ) {
memory_space *local_mem = NULL;
ptx_thread_info *thd = new ptx_thread_info();
-
- unsigned lm_idx = blockDim.x*blockDim.y*tz + blockDim.x * ty + tx;
+ dim3 tid3d = kernel.get_next_thread_id_3d();
+ unsigned lm_idx = kernel.get_next_thread_id();
+ kernel.increment_thread_id();
std::map<unsigned,memory_space*>::iterator lm=lm_lookup.find(lm_idx);
if ( lm == lm_lookup.end() ) {
char buf[1024];
- snprintf(buf,1024,"local_(%u,%u,%u)", tx, ty, tz );
+ snprintf(buf,1024,"local_(%u,%u,%u)", tid3d.x, tid3d.y, tid3d.z );
local_mem = new memory_space_impl<32>(buf,32);
lm_lookup[lm_idx] = local_mem;
} else {
local_mem = lm->second;
}
-
- thd->set_info(g_func_info);
- thd->set_nctaid(gridDim.x,gridDim.y,gridDim.z);
- thd->set_ntid(blockDim.x, blockDim.y, blockDim.z);
- thd->set_ctaid(gx,gy,gz);
- thd->set_tid(tx,ty,tz);
+ thd->set_info(finfo);
+ thd->set_nctaid(ctaid3d);
+ thd->set_ntid(kernel.get_cta_dim());
+ thd->set_ctaid(ctaid3d);
+ thd->set_tid(tid3d);
thd->set_valid();
thd->m_shared_mem = shared_mem;
thd->m_local_mem = local_mem;
thd->m_cta_info = g_func_cta_info;
g_func_cta_info->add_thread(thd);
active_threads.push_back(thd);
- }
- }
}
while ( !(active_threads.empty() && blocked_threads.empty()) ) {
@@ -1720,22 +1659,12 @@ void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 bl
break;
}
- unsigned op_type;
- addr_t addr;
- unsigned cycles;
- memory_space_t space;
- int arch_reg[MAX_REG_OPERANDS] = { -1 };
- unsigned data_size;
- dram_callback_t callback;
- unsigned warp_active_mask = (unsigned)-1; // vote instruction with diverged warps won't execute correctly
- // in functional simulation mode
-
- g_func_info->ptx_decode_inst( thread, &op_type, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg, &pred, &ar1, &ar2 );
- g_func_info->ptx_exec_inst( thread, &addr, &space, &data_size, &cycles, &callback, warp_active_mask );
+ 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 );
}
}
- }
- }
}
printf( "GPGPU-Sim: Done functional simulation (%u instructions simulated).\n", g_ptx_sim_num_insn );
if ( gpgpu_ptx_instruction_classification ) {
@@ -1757,70 +1686,12 @@ void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 bl
fflush(stdout);
}
-void ptx_decode_inst( void *thd, unsigned *op, int *i1, int *i2, int *i3, int *i4, int *o1, int *o2, int *o3, int *o4, int *vectorin, int *vectorout, int *arch_reg, int *pred, int *ar1, int *ar2 )
-{
- *op = NO_OP;
- *o1 = 0;
- *o2 = 0;
- *o3 = 0;
- *o4 = 0;
- *i1 = 0;
- *i2 = 0;
- *i3 = 0;
- *i4 = 0;
- *vectorin = 0;
- *vectorout = 0;
- std::fill_n(arch_reg, MAX_REG_OPERANDS, -1);
- *pred = 0;
- *ar1 = 0;
- *ar2 = 0;
-
- if ( thd == NULL )
- return;
-
- ptx_thread_info *thread = (ptx_thread_info *) thd;
- g_func_info = thread->func_info();
- g_func_info->ptx_decode_inst(thread,op,i1,i2,i3,i4,o1,o2,o3,o4,vectorin,vectorout,arch_reg,pred,ar1,ar2);
-}
-
-extern "C" unsigned ptx_get_inst_op( void *thd)
-{
- if ( thd == NULL )
- return NO_OP;
-
- ptx_thread_info *thread = (ptx_thread_info *) thd;
- return(thread->func_info())->ptx_get_inst_op(thread);
-}
-
-void ptx_exec_inst( void *thd, address_type *addr, memory_space_t *space, unsigned *data_size, unsigned *cycles, dram_callback_t* callback, unsigned warp_active_mask )
-{
- if ( thd == NULL )
- return;
- *cycles = 1;
- ptx_thread_info *thread = (ptx_thread_info *) thd;
- g_func_info = thread->func_info();
- g_func_info->ptx_exec_inst( thread, addr, space, data_size, cycles, callback, warp_active_mask );
-}
-
-void ptx_dump_regs( void *thd )
-{
- if ( thd == NULL )
- return;
- ptx_thread_info *t = (ptx_thread_info *) thd;
- t->dump_regs(stdout);
-}
-
unsigned ptx_set_tex_cache_linesize(unsigned linesize)
{
g_texcache_linesize = linesize;
return 0;
}
-unsigned ptx_kernel_program_size()
-{
- return g_func_info->get_function_size();
-}
-
unsigned translate_pc_to_ptxlineno(unsigned pc)
{
// this function assumes that the kernel fits inside a single PTX file
@@ -1837,12 +1708,11 @@ int g_ptxinfo_error_detected;
static char *g_ptxinfo_kname = NULL;
static struct gpgpu_ptx_sim_kernel_info g_ptxinfo_kinfo;
+static void clear_ptxinfo();
+
extern "C" void ptxinfo_function(const char *fname )
{
- g_ptxinfo_kinfo.regs=0;
- g_ptxinfo_kinfo.lmem=0;
- g_ptxinfo_kinfo.smem=0;
- g_ptxinfo_kinfo.cmem=0;
+ clear_ptxinfo();
g_ptxinfo_kname = strdup(fname);
}
@@ -1874,6 +1744,8 @@ void clear_ptxinfo()
g_ptxinfo_kinfo.lmem=0;
g_ptxinfo_kinfo.smem=0;
g_ptxinfo_kinfo.cmem=0;
+ g_ptxinfo_kinfo.ptx_version=0;
+ g_ptxinfo_kinfo.sm_target=0;
}
void ptxinfo_opencl_addinfo( std::map<std::string,function_info*> &kernels )
@@ -1991,14 +1863,9 @@ unsigned int get_converge_point( unsigned int pc, void *thd )
abort(); // returning garbage!
}
-void find_reconvergence_points()
-{
- find_reconvergence_points(g_func_info);
-}
-
-void dwf_process_reconv_pts()
+void dwf_process_reconv_pts(function_info *entry)
{
- rec_pts tmp = find_reconvergence_points(g_func_info);
+ 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 d7d3f8a..57f2837 100644
--- a/src/cuda-sim/cuda-sim.h
+++ b/src/cuda-sim/cuda-sim.h
@@ -23,15 +23,15 @@ extern int g_ptx_kernel_count; // used for classification stat collection purpos
extern FILE* ptx_inst_debug_file;
-extern void gpgpu_cuda_ptx_sim_init_grid( const char *kernel_key,
- struct gpgpu_ptx_sim_arg *args,
+extern class kernel_info_t gpgpu_cuda_ptx_sim_init_grid( const char *kernel_key,
+ gpgpu_ptx_sim_arg_list_t args,
struct dim3 gridDim,
struct dim3 blockDim );
-extern void gpgpu_opencl_ptx_sim_init_grid(class function_info *entry,
- struct gpgpu_ptx_sim_arg *args,
+extern class kernel_info_t gpgpu_opencl_ptx_sim_init_grid(class function_info *entry,
+ gpgpu_ptx_sim_arg_list_t args,
struct dim3 gridDim,
struct dim3 blockDim );
-extern void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 blockDim, struct gpgpu_ptx_sim_arg *);
+extern void gpgpu_cuda_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 blockDim, gpgpu_ptx_sim_arg_list_t );
extern void print_splash();
extern void* gpgpu_ptx_sim_malloc( size_t count );
extern void* gpgpu_ptx_sim_mallocarray( size_t count );
@@ -55,8 +55,8 @@ extern void read_sim_environment_variables();
extern void register_function_implementation( const char *name, function_info *impl );
extern void ptxinfo_cuda_addinfo();
extern void ptxinfo_opencl_addinfo( std::map<std::string,function_info*> &kernels );
-extern void ptx_sim_free_sm( class ptx_thread_info** thread_info );
-unsigned ptx_sim_init_thread( class ptx_thread_info** thread_info,
+unsigned ptx_sim_init_thread( kernel_info_t &kernel,
+ class ptx_thread_info** thread_info,
int sid,
unsigned tid,
unsigned threads_left,
@@ -64,12 +64,9 @@ unsigned ptx_sim_init_thread( class ptx_thread_info** thread_info,
class core_t *core,
unsigned hw_cta_id,
unsigned hw_warp_id );
-unsigned ptx_sim_cta_size();
-const struct gpgpu_ptx_sim_kernel_info* ptx_sim_kernel_info();
-void set_option_gpgpu_spread_blocks_across_cores(int option);
-int ptx_thread_done( void *thd );
+const 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 );
-int ptx_thread_get_next_pc( void *thd );
void* ptx_thread_get_next_finfo( void *thd );
int ptx_thread_at_barrier( void *thd );
int ptx_thread_all_at_barrier( void *thd );
@@ -78,28 +75,10 @@ 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 ptx_decode_inst( void *thd,
- unsigned *op,
- int *i1,
- int *i2,
- int *i3,
- int *i4,
- int *o1,
- int *o2,
- int *o3,
- int *o4,
- int *vectorin,
- int *vectorout,
- int *arch_reg,
- int *pred,
- int *ar1,
- int *ar2 );
-void ptx_exec_inst( void *thd,
- address_type *addr,
- memory_space_t *space,
- unsigned *data_size,
- unsigned *cycles,
- dram_callback_t* callback,
- unsigned warp_active_mask );
+
+function_info *get_kernel(const char *kernel_key, std::string &kernel_func_name_mangled );
+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);
#endif
diff --git a/src/cuda-sim/dram_callback.h b/src/cuda-sim/dram_callback.h
index 9336ee0..fee97eb 100644
--- a/src/cuda-sim/dram_callback.h
+++ b/src/cuda-sim/dram_callback.h
@@ -75,10 +75,4 @@
#ifndef __DRAM_CALLBACK_H__
#define __DRAM_CALLBACK_H__
-typedef struct {
- void (*function)(void* pI, void* gOldGThread);
- void* instruction;
- void* thread;// callback has to abuse g_thread when executed
-}dram_callback_t;
-
#endif // #ifndef __DRAM_CALLBACK_H__
diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc
index d9a9630..78996bb 100644
--- a/src/cuda-sim/instructions.cc
+++ b/src/cuda-sim/instructions.cc
@@ -651,16 +651,20 @@ void ptx_thread_info::set_vector_operand_values( const operand_info &dst,
const ptx_reg_t &data1,
const ptx_reg_t &data2,
const ptx_reg_t &data3,
- const ptx_reg_t &data4,
- unsigned num_elements )
+ const ptx_reg_t &data4 )
{
- set_reg(dst.vec_symbol(0), data1);
- set_reg(dst.vec_symbol(1), data2);
- if (num_elements > 2) {
- set_reg(dst.vec_symbol(2), data3);
- if (num_elements > 3) {
- set_reg(dst.vec_symbol(3), data4);
- }
+ unsigned num_elements = dst.get_vect_nelem();
+ if (num_elements > 0) {
+ set_reg(dst.vec_symbol(0), data1);
+ if (num_elements > 1) {
+ set_reg(dst.vec_symbol(1), data2);
+ if (num_elements > 2) {
+ set_reg(dst.vec_symbol(2), data3);
+ if (num_elements > 3) {
+ set_reg(dst.vec_symbol(3), data4);
+ }
+ }
+ }
}
m_last_set_operand_value = data1;
@@ -1084,6 +1088,8 @@ void atom_callback( void* ptx_inst, void* thd )
// Write operation result into global memory
// (i.e. copy src1_data to dst)
g_global_mem->write(src1_data.u32,size/8,&op_result.s64,thread,pI);
+ gpgpu_sim *gpu = thread->get_gpu();
+ gpu->decrement_atomic_count(thread->get_hw_sid(),thread->get_hw_wid());
}
// atom_impl will now result in a callback being called in mem_ctrl_pop (gpu-sim.c)
@@ -1113,7 +1119,7 @@ void bar_sync_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
const operand_info &dst = pI->dst();
ptx_reg_t b = thread->get_operand_value(dst, dst, U32_TYPE, thread, 1);
- assert( b.u32 == 0 ); // not clear what should happen if this is not zero
+ assert( b.u32 == 0 ); // support for bar.sync a{,b}; where a != 0 not yet implemented
}
void bfe_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
@@ -1194,20 +1200,80 @@ void call_impl( const ptx_instruction *pI, ptx_thread_info *thread )
unsigned sid = thread->get_hw_sid();
unsigned tid = thread->get_hw_tid();
+ gpgpu_sim *gpu = thread->get_gpu();
unsigned callee_pc=0, callee_rpc=0;
- if( gpgpu_simd_model == POST_DOMINATOR ) {
- get_pdom_stack_top_info(sid,tid,&callee_pc,&callee_rpc);
+ if( gpu->simd_model() == POST_DOMINATOR ) {
+ gpu->get_pdom_stack_top_info(sid,tid,&callee_pc,&callee_rpc);
assert( callee_pc == thread->get_pc() );
}
- thread->callstack_push(callee_pc+1,callee_rpc,return_var_src,return_var_dst,call_uid_next++);
+ thread->callstack_push(callee_pc + pI->inst_size(), callee_rpc, return_var_src, return_var_dst, call_uid_next++);
copy_buffer_list_into_frame(thread, arg_values);
thread->set_npc(target_func);
}
-void clz_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+//Ptxplus version of call instruction. Jumps to a label not a different Kernel.
+void callp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+
+ static unsigned call_uid_next = 1;
+
+ const operand_info &target = pI->dst();
+ ptx_reg_t target_pc = thread->get_operand_value(target, target, U32_TYPE, thread, 1);
+
+ const symbol *return_var_src = NULL;
+ const symbol *return_var_dst = NULL;
+
+ unsigned sid = thread->get_hw_sid();
+ unsigned tid = thread->get_hw_tid();
+ gpgpu_sim *gpu = thread->get_gpu();
+ unsigned callee_pc=0, callee_rpc=0;
+ if( gpu->simd_model() == POST_DOMINATOR ) {
+ gpu->get_pdom_stack_top_info(sid,tid,&callee_pc,&callee_rpc);
+ assert( callee_pc == thread->get_pc() );
+ }
+
+ thread->callstack_push_plus(callee_pc + pI->inst_size(), callee_rpc, return_var_src, return_var_dst, call_uid_next++);
+ thread->set_npc(target_pc);
+}
+
+void clz_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+ int max;
+ unsigned long long mask;
+ d.u64 = 0;
+
+ switch ( i_type ) {
+ case B32_TYPE:
+ max = 32;
+ mask = 0x80000000;
+ break;
+ case B64_TYPE:
+ max = 64;
+ mask = 0x8000000000000000;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ while ((d.u32 < max) && ((a.u64&mask) == 0) ) {
+ d.u32++;
+ a.u64 = a.u64 << 1;
+ }
+
+ thread->set_operand_value(dst,d, B32_TYPE, thread, pI);
+}
void cnot_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
@@ -1313,7 +1379,7 @@ ptx_reg_t f2x( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign,
ptx_reg_t y;
if ( to_sign == 1 ) { // convert to 64-bit number first?
- int tmp = cuda_math::__internal_float2int(x.f32, mode);
+ int tmp = cuda_math::float2int(x.f32, mode);
if ((x.u32 & 0x7f800000) == 0)
tmp = 0; // round denorm. FP to 0
if (saturation_mode && to_width < 32) {
@@ -1327,7 +1393,7 @@ ptx_reg_t f2x( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign,
default: assert(0); break;
}
} else if ( to_sign == 0 ) {
- unsigned int tmp = cuda_math::__internal_float2uint(x.f32, mode);
+ unsigned int tmp = cuda_math::float2uint(x.f32, mode);
if ((x.u32 & 0x7f800000) == 0)
tmp = 0; // round denorm. FP to 0
if (saturation_mode && to_width < 32) {
@@ -1432,10 +1498,10 @@ ptx_reg_t s2f( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign,
case 16: assert(0); break;
case 32:
switch (rounding_mode) {
- case RZ_OPTION: y.f32 = cuda_math::__ll2float_rn(y.s64); break;
+ case RZ_OPTION: y.f32 = cuda_math::__ll2float_rz(y.s64); break;
case RN_OPTION: y.f32 = cuda_math::__ll2float_rn(y.s64); break;
- case RM_OPTION: y.f32 = cuda_math::__ll2float_rn(y.s64); break;
- case RP_OPTION: y.f32 = cuda_math::__ll2float_rn(y.s64); break;
+ case RM_OPTION: y.f32 = cuda_math::__ll2float_rd(y.s64); break;
+ case RP_OPTION: y.f32 = cuda_math::__ll2float_ru(y.s64); break;
default: break;
}
break;
@@ -1549,9 +1615,9 @@ ptx_reg_t d2d( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign,
break;
case RNI_OPTION:
#if CUDART_VERSION >= 3000
- y.f64 = nearbyint(x.f32);
+ y.f64 = nearbyint(x.f64);
#else
- y.f64 = cuda_math::__internal_nearbyint(x.f64);
+ y.f64 = cuda_math::__internal_nearbyintf(x.f64);
#endif
break;
case RMI_OPTION:
@@ -1816,7 +1882,8 @@ void cvta_impl( const ptx_instruction *pI, ptx_thread_info *thread )
} else {
switch( space.get_type() ) {
case shared_space: to_addr_hw = shared_to_generic( smid, from_addr_hw ); break;
- case local_space: to_addr_hw = local_to_generic( smid, hwtid, from_addr_hw ); break;
+ case local_space: to_addr_hw = local_to_generic( smid, hwtid, from_addr_hw )
+ + thread->get_local_mem_stack_pointer(); break; // add stack ptr here so that it can be passed as a pointer at function call
case global_space: to_addr_hw = global_to_generic( from_addr_hw ); break;
default: abort();
}
@@ -2018,11 +2085,11 @@ void ld_exec( const ptx_instruction *pI, ptx_thread_info *thread )
mem->read(addr+2*size/8,size/8,&data3.s64);
if (vector_spec != V3_TYPE) { //v4
mem->read(addr+3*size/8,size/8,&data4.s64);
- thread->set_vector_operand_values(dst,data1,data2,data3,data4, 4);
+ thread->set_vector_operand_values(dst,data1,data2,data3,data4);
} else //v3
- thread->set_vector_operand_values(dst,data1,data2,data3,data3,3);
+ thread->set_vector_operand_values(dst,data1,data2,data3,data3);
} else //v2
- thread->set_vector_operand_values(dst,data1,data2,data2,data2,2);
+ thread->set_vector_operand_values(dst,data1,data2,data2,data2);
}
thread->m_last_effective_address = addr;
thread->m_last_memory_space = space;
@@ -2249,7 +2316,10 @@ void max_impl( const ptx_instruction *pI, ptx_thread_info *thread )
thread->set_operand_value(dst,d, i_type, thread, pI);
}
-void membar_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void membar_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ // handled by timing simulator
+}
void min_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
@@ -2332,16 +2402,16 @@ void mov_impl( const ptx_instruction *pI, ptx_thread_info *thread )
unsigned bits_per_dst_elem = nbits_to_move / nelem;
for( unsigned i=0; i < nelem; i++ ) {
switch(bits_per_dst_elem) {
- case 8: v[i].u8 = tmp_bits.u64 & (((unsigned long long) 0xFF) << (8*i)); break;
- case 16: v[i].u16 = tmp_bits.u64 & (((unsigned long long) 0xFFFF) << (16*i)); break;
- case 32: v[i].u32 = tmp_bits.u64 & (((unsigned long long) 0xFFFFFFFF) << (32*i)); break;
+ case 8: v[i].u8 = (tmp_bits.u64 >> (8*i)) & ((unsigned long long) 0xFF); break;
+ case 16: v[i].u16 = (tmp_bits.u64 >> (16*i)) & ((unsigned long long) 0xFFFF); break;
+ case 32: v[i].u32 = (tmp_bits.u64 >> (32*i)) & ((unsigned long long) 0xFFFFFFFF); break;
default:
printf("Execution error: mov pack/unpack with unsupported source/dst size ratio (dst)\n");
assert(0);
break;
}
}
- thread->set_vector_operand_values(dst,v[0],v[1],v[2],v[3],nelem);
+ thread->set_vector_operand_values(dst,v[0],v[1],v[2],v[3]);
} else {
thread->set_operand_value(dst,tmp_bits, i_type, thread, pI);
}
@@ -2707,6 +2777,19 @@ void ret_impl( const ptx_instruction *pI, ptx_thread_info *thread )
}
}
+//Ptxplus version of ret instruction.
+void retp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ bool empty = thread->callstack_pop_plus();
+ if( empty ) {
+ core_t *sc = thread->get_core();
+ unsigned warp_id = thread->get_hw_wid();
+ sc->warp_exit(warp_id);
+ thread->m_cta_info->register_thread_exit(thread);
+ thread->set_done();
+ }
+}
+
void rsqrt_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
ptx_reg_t a, d;
@@ -3689,7 +3772,7 @@ void tex_impl( const ptx_instruction *pI, ptx_thread_info *thread )
assert(0);
}
thread->m_last_memory_space = tex_space;
- thread->set_vector_operand_values(dst,data1,data2,data3,data4,4);
+ thread->set_vector_operand_values(dst,data1,data2,data3,data4);
}
void txq_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
@@ -3792,10 +3875,6 @@ void inst_not_implemented( const ptx_instruction * pI )
abort();
}
-void print_instruction(const ptx_instruction *instruction)
-{
-}
-
ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo, operand_info dstInfo, unsigned type, ptx_thread_info *thread)
{
ptx_reg_t result;
diff --git a/src/cuda-sim/memory.cc b/src/cuda-sim/memory.cc
index b825f12..aecfd31 100644
--- a/src/cuda-sim/memory.cc
+++ b/src/cuda-sim/memory.cc
@@ -83,10 +83,35 @@ template<unsigned BSIZE> memory_space_impl<BSIZE>::memory_space_impl( std::strin
template<unsigned BSIZE> void memory_space_impl<BSIZE>::write( mem_addr_t addr, size_t length, const void *data, class ptx_thread_info *thd, const ptx_instruction *pI)
{
mem_addr_t index = addr >> m_log2_block_size;
- unsigned offset = addr & (BSIZE-1);
- unsigned nbytes = length;
- assert( (addr+length) <= (index+1)*BSIZE );
- m_data[index].write(offset,nbytes,(const unsigned char*)data);
+ if ( (addr+length) <= (index+1)*BSIZE ) {
+ // fast route for intra-block access
+ unsigned offset = addr & (BSIZE-1);
+ unsigned nbytes = length;
+ m_data[index].write(offset,nbytes,(const unsigned char*)data);
+ } else {
+ // slow route for inter-block access
+ unsigned nbytes_remain = length;
+ unsigned src_offset = 0;
+ mem_addr_t current_addr = addr;
+
+ while (nbytes_remain > 0) {
+ unsigned offset = current_addr & (BSIZE-1);
+ mem_addr_t page = current_addr >> m_log2_block_size;
+ mem_addr_t access_limit = offset + nbytes_remain;
+ if (access_limit > BSIZE) {
+ access_limit = BSIZE;
+ }
+
+ size_t tx_bytes = access_limit - offset;
+ m_data[page].write(offset, tx_bytes, &((const unsigned char*)data)[src_offset]);
+
+ // advance pointers
+ src_offset += tx_bytes;
+ current_addr += tx_bytes;
+ nbytes_remain -= tx_bytes;
+ }
+ assert(nbytes_remain == 0);
+ }
if( !m_watchpoints.empty() ) {
std::map<unsigned,mem_addr_t>::iterator i;
for( i=m_watchpoints.begin(); i!=m_watchpoints.end(); i++ ) {
@@ -97,28 +122,59 @@ template<unsigned BSIZE> void memory_space_impl<BSIZE>::write( mem_addr_t addr,
}
}
-template<unsigned BSIZE> void memory_space_impl<BSIZE>::read( mem_addr_t addr, size_t length, void *data ) const
+template<unsigned BSIZE> void memory_space_impl<BSIZE>::read_single_block( mem_addr_t blk_idx, mem_addr_t addr, size_t length, void *data) const
{
- mem_addr_t index = addr >> m_log2_block_size;
- unsigned offset = addr & (BSIZE-1);
- unsigned nbytes = length;
- typename map_t::const_iterator i = m_data.find(index);
- if( (addr+length) > (index+1)*BSIZE ) {
+ if ((addr + length) > (blk_idx + 1) * BSIZE) {
printf("GPGPU-Sim PTX: ERROR * access to memory \'%s\' is unaligned : addr=0x%x, length=%zu\n",
m_name.c_str(), addr, length);
printf("GPGPU-Sim PTX: (addr+length)=0x%lx > 0x%x=(index+1)*BSIZE, index=0x%x, BSIZE=0x%x\n",
- (addr+length),(index+1)*BSIZE, index, BSIZE);
+ (addr+length),(blk_idx+1)*BSIZE, blk_idx, BSIZE);
throw 1;
}
+ typename map_t::const_iterator i = m_data.find(blk_idx);
if( i == m_data.end() ) {
for( size_t n=0; n < length; n++ )
((unsigned char*)data)[n] = (unsigned char) 0;
//printf("GPGPU-Sim PTX: WARNING reading %zu bytes from unititialized memory at address 0x%x in space %s\n", length, addr, m_name.c_str() );
} else {
+ unsigned offset = addr & (BSIZE-1);
+ unsigned nbytes = length;
i->second.read(offset,nbytes,(unsigned char*)data);
}
}
+template<unsigned BSIZE> void memory_space_impl<BSIZE>::read( mem_addr_t addr, size_t length, void *data ) const
+{
+ mem_addr_t index = addr >> m_log2_block_size;
+ if ((addr+length) <= (index+1)*BSIZE ) {
+ // fast route for intra-block access
+ read_single_block(index, addr, length, data);
+ } else {
+ // slow route for inter-block access
+ unsigned nbytes_remain = length;
+ unsigned dst_offset = 0;
+ mem_addr_t current_addr = addr;
+
+ while (nbytes_remain > 0) {
+ unsigned offset = current_addr & (BSIZE-1);
+ mem_addr_t page = current_addr >> m_log2_block_size;
+ mem_addr_t access_limit = offset + nbytes_remain;
+ if (access_limit > BSIZE) {
+ access_limit = BSIZE;
+ }
+
+ size_t tx_bytes = access_limit - offset;
+ read_single_block(page, current_addr, tx_bytes, &((unsigned char*)data)[dst_offset]);
+
+ // advance pointers
+ dst_offset += tx_bytes;
+ current_addr += tx_bytes;
+ nbytes_remain -= tx_bytes;
+ }
+ assert(nbytes_remain == 0);
+ }
+}
+
template<unsigned BSIZE> void memory_space_impl<BSIZE>::print( const char *format, FILE *fout ) const
{
typename map_t::const_iterator i_page;
diff --git a/src/cuda-sim/memory.h b/src/cuda-sim/memory.h
index bac4d24..4487b36 100644
--- a/src/cuda-sim/memory.h
+++ b/src/cuda-sim/memory.h
@@ -164,6 +164,7 @@ public:
virtual void set_watch( addr_t addr, unsigned watchpoint );
private:
+ void read_single_block( mem_addr_t blk_idx, mem_addr_t addr, size_t length, void *data) const;
std::string m_name;
unsigned m_log2_block_size;
typedef mem_map<mem_addr_t,mem_storage<BSIZE> > map_t;
diff --git a/src/cuda-sim/opcodes.def b/src/cuda-sim/opcodes.def
index c1217ee..5f9caaa 100644
--- a/src/cuda-sim/opcodes.def
+++ b/src/cuda-sim/opcodes.def
@@ -77,7 +77,7 @@ OP_DEF(ADD_OP,add_impl,"add",1,1)
OP_DEF(ADDC_OP,addc_impl,"addc",1,1)
OP_DEF(AND_OP,and_impl,"and",1,1)
OP_DEF(ANDN_OP,andn_impl,"andn",1,1)
-OP_DEF(ATOM_OP,atom_impl,"atom",0,3)
+OP_DEF(ATOM_OP,atom_impl,"atom",1,3)
OP_DEF(BAR_OP,bar_sync_impl,"bar.sync",1,3)
OP_DEF(BFE_OP,bfe_impl,"bfe",1,1)
OP_DEF(BFI_OP,bfi_impl,"bfi",1,1)
@@ -86,6 +86,7 @@ OP_DEF(BRA_OP,bra_impl,"bra",0,3)
OP_DEF(BREV_OP,brev_impl,"brev",1,1)
OP_DEF(BRKPT_OP,brkpt_impl,"brkpt",1,9)
OP_DEF(CALL_OP,call_impl,"call",1,3)
+OP_DEF(CALLP_OP,callp_impl,"callp",1,3)
OP_DEF(CLZ_OP,clz_impl,"clz",1,1)
OP_DEF(CNOT_OP,cnot_impl,"cnot",1,1)
OP_DEF(COS_OP,cos_impl,"cos",1,4)
@@ -122,6 +123,7 @@ OP_DEF(RCP_OP,rcp_impl,"rcp",1,4)
OP_DEF(RED_OP,red_impl,"red",1,7)
OP_DEF(REM_OP,rem_impl,"rem",1,1)
OP_DEF(RET_OP,ret_impl,"ret",0,3)
+OP_DEF(RETP_OP,retp_impl,"retp",0,3)
OP_DEF(RSQRT_OP,rsqrt_impl,"rsqrt",1,4)
OP_DEF(SAD_OP,sad_impl,"sad",1,1)
OP_DEF(SELP_OP,selp_impl,"selp",1,1)
diff --git a/src/cuda-sim/ptx-stats.cc b/src/cuda-sim/ptx-stats.cc
index 567c62b..40e574a 100644
--- a/src/cuda-sim/ptx-stats.cc
+++ b/src/cuda-sim/ptx-stats.cc
@@ -67,9 +67,6 @@
#include <map>
#include "../tr1_hash_map.h"
-// external dependencies
-extern function_info *g_func_info;
-
// options
bool enable_ptx_file_line_stats;
char * ptx_line_stats_filename = NULL;
@@ -192,7 +189,7 @@ void ptx_file_line_stats_add_exec_count(const ptx_instruction *pInsn)
// attribute pipeline latency to this ptx instruction (specified by the pc)
// pipeline latency is the number of cycles a warp with this instruction spent in the pipeline
-void ptx_file_line_stats_add_latency(void * ptx_thd, unsigned pc, unsigned latency)
+void ptx_file_line_stats_add_latency(unsigned pc, unsigned latency)
{
const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
@@ -210,7 +207,7 @@ void ptx_file_line_stats_add_dram_traffic(unsigned pc, unsigned dram_traffic)
// attribute the number of shared memory access cycles to a ptx instruction
// counts both the number of warps doing shared memory access and the number of cycles involved
-void ptx_file_line_stats_add_smem_bank_conflict(void * ptx_thd, unsigned pc, unsigned n_way_bkconflict)
+void ptx_file_line_stats_add_smem_bank_conflict(unsigned pc, unsigned n_way_bkconflict)
{
const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
@@ -221,7 +218,7 @@ void ptx_file_line_stats_add_smem_bank_conflict(void * ptx_thd, unsigned pc, uns
// attribute a non-coalesced mem access to a ptx instruction
// counts both the number of warps causing this and the number of memory requests generated
-void ptx_file_line_stats_add_uncoalesced_gmem(void * ptx_thd, unsigned pc, unsigned n_access)
+void ptx_file_line_stats_add_uncoalesced_gmem(unsigned pc, unsigned n_access)
{
const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
diff --git a/src/cuda-sim/ptx-stats.h b/src/cuda-sim/ptx-stats.h
index 004433b..019586c 100644
--- a/src/cuda-sim/ptx-stats.h
+++ b/src/cuda-sim/ptx-stats.h
@@ -78,10 +78,10 @@ void ptx_file_line_stats_add_exec_count(const ptx_instruction *pInsn);
#endif
// stat collection interface to gpgpu-sim
-void ptx_file_line_stats_add_latency(void * ptx_thd, unsigned pc, unsigned latency);
+void ptx_file_line_stats_add_latency(unsigned pc, unsigned latency);
void ptx_file_line_stats_add_dram_traffic(unsigned pc, unsigned dram_traffic);
-void ptx_file_line_stats_add_smem_bank_conflict(void * ptx_thd, unsigned pc, unsigned n_way_bkconflict);
-void ptx_file_line_stats_add_uncoalesced_gmem(void * ptx_thd, unsigned pc, unsigned n_access);
+void ptx_file_line_stats_add_smem_bank_conflict(unsigned pc, unsigned n_way_bkconflict);
+void ptx_file_line_stats_add_uncoalesced_gmem(unsigned pc, unsigned n_access);
void ptx_file_line_stats_create_exposed_latency_tracker(int n_shader_cores);
void ptx_file_line_stats_add_inflight_memory_insn(int sc_id, unsigned pc);
diff --git a/src/cuda-sim/ptx.l b/src/cuda-sim/ptx.l
index 82daef9..1b87c7d 100644
--- a/src/cuda-sim/ptx.l
+++ b/src/cuda-sim/ptx.l
@@ -98,6 +98,7 @@ bra TC; ptx_lval.int_value = BRA_OP; return OPCODE;
brev TC; ptx_lval.int_value = BREV_OP; return OPCODE;
brkpt TC; ptx_lval.int_value = BRKPT_OP; return OPCODE;
call TC; ptx_lval.int_value = CALL_OP; return OPCODE;
+callp TC; ptx_lval.int_value = CALLP_OP; return OPCODE;
clz TC; ptx_lval.int_value = CLZ_OP; return OPCODE;
cnot TC; ptx_lval.int_value = CNOT_OP; return OPCODE;
cos TC; ptx_lval.int_value = COS_OP; return OPCODE;
@@ -135,6 +136,7 @@ rcp TC; ptx_lval.int_value = RCP_OP; return OPCODE;
red TC; ptx_lval.int_value = RED_OP; return OPCODE;
rem TC; ptx_lval.int_value = REM_OP; return OPCODE;
ret TC; ptx_lval.int_value = RET_OP; return OPCODE;
+retp TC; ptx_lval.int_value = RETP_OP; return OPCODE;
rsqrt TC; ptx_lval.int_value = RSQRT_OP; return OPCODE;
sad TC; ptx_lval.int_value = SAD_OP; return OPCODE;
selp TC; ptx_lval.int_value = SELP_OP; return OPCODE;
@@ -263,7 +265,7 @@ breakaddr TC; ptx_lval.int_value = BREAKADDR_OP; return OPCODE;
\.bb128 TC; return BB128_TYPE;
\.pred TC; return PRED_TYPE;
-\.texref TC; return TEXREF_TYPE;
+\.texref TC; BEGIN(NOT_OPCODE); return TEXREF_TYPE;
\.samplerref TC; return SAMPLERREF_TYPE;
\.surfref TC; return SURFREF_TYPE;
@@ -271,6 +273,8 @@ breakaddr TC; ptx_lval.int_value = BREAKADDR_OP; return OPCODE;
\.v3 TC; return V3_TYPE;
\.v4 TC; return V4_TYPE;
+\.half TC; return HALF_OPTION; /* ptxplus */
+
\.equ TC; return EQU_OPTION;
\.neu TC; return NEU_OPTION;
\.ltu TC; return LTU_OPTION;
@@ -322,6 +326,7 @@ breakaddr TC; ptx_lval.int_value = BREAKADDR_OP; return OPCODE;
\.all TC; return ALL_OPTION;
\.gl TC; return GLOBAL_OPTION;
\.cta TC; return CTA_OPTION;
+\.sys TC; return SYS_OPTION;
\.exit TC; return EXIT_OPTION;
@@ -368,11 +373,11 @@ breakaddr TC; ptx_lval.int_value = BREAKADDR_OP; return OPCODE;
">" TC; return RIGHT_ANGLE_BRACKET;
"(" TC; return LEFT_PAREN;
")" TC; return RIGHT_PAREN;
-":" TC; return COLON;
+":" TC; BEGIN(INITIAL); return COLON;
";" TC; BEGIN(INITIAL); return SEMI_COLON;
"!" TC; return EXCLAMATION;
"=" TC; return EQUALS;
-"{" TC; BEGIN(INITIAL); return LEFT_BRACE;
+"{" TC; return LEFT_BRACE;
"}" TC; return RIGHT_BRACE;
\. TC; return PERIOD;
"/" TC; return BACKSLASH;
diff --git a/src/cuda-sim/ptx.y b/src/cuda-sim/ptx.y
index 1551f22..833e082 100644
--- a/src/cuda-sim/ptx.y
+++ b/src/cuda-sim/ptx.y
@@ -133,6 +133,7 @@
%token V4_TYPE
%token COMMA
%token PRED
+%token HALF_OPTION
%token EQ_OPTION
%token NE_OPTION
%token LT_OPTION
@@ -205,6 +206,7 @@
%token ALL_OPTION
%token GLOBAL_OPTION
%token CTA_OPTION
+%token SYS_OPTION
%token EXIT_OPTION
%token ABS_OPTION
%token TO_OPTION
@@ -260,7 +262,8 @@ function_decl_header: ENTRY_DIRECTIVE { $$ = 1; g_func_decl=1; func_header(".ent
| EXTERN_DIRECTIVE FUNC_DIRECTIVE { $$ = 2; g_func_decl=1; func_header(".func"); }
;
-param_list: param_entry { add_directive(); }
+param_list: /*empty*/
+ | param_entry { add_directive(); }
| param_list COMMA {func_header_info(",");} param_entry { add_directive(); }
param_entry: PARAM_DIRECTIVE { add_space_spec(param_space_unclassified,0); } variable_spec identifier_spec { add_function_arg(); }
@@ -277,8 +280,10 @@ statement_list: directive_statement { add_directive(); }
;
directive_statement: variable_declaration SEMI_COLON
- | VERSION_DIRECTIVE DOUBLE_OPERAND { add_version_info($2); }
+ | VERSION_DIRECTIVE DOUBLE_OPERAND { add_version_info($2, 0); }
+ | VERSION_DIRECTIVE DOUBLE_OPERAND PLUS { add_version_info($2,1); }
| TARGET_DIRECTIVE IDENTIFIER COMMA IDENTIFIER { target_header2($2,$4); }
+ | TARGET_DIRECTIVE IDENTIFIER COMMA IDENTIFIER COMMA IDENTIFIER { target_header3($2,$4,$6); }
| TARGET_DIRECTIVE IDENTIFIER { target_header($2); }
| FILE_DIRECTIVE INT_OPERAND STRING { add_file($2,$3); }
| LOC_DIRECTIVE INT_OPERAND INT_OPERAND INT_OPERAND
@@ -416,6 +421,7 @@ option: type_spec
| ALL_OPTION { add_option(ALL_OPTION); }
| GLOBAL_OPTION { add_option(GLOBAL_OPTION); }
| CTA_OPTION { add_option(CTA_OPTION); }
+ | SYS_OPTION { add_option(SYS_OPTION); }
| GEOM_MODIFIER_1D { add_option(GEOM_MODIFIER_1D); }
| GEOM_MODIFIER_2D { add_option(GEOM_MODIFIER_2D); }
| GEOM_MODIFIER_3D { add_option(GEOM_MODIFIER_3D); }
@@ -428,6 +434,7 @@ option: type_spec
| ABS_OPTION { add_option(ABS_OPTION); }
| atomic_operation_spec ;
| TO_OPTION { add_option(TO_OPTION); }
+ | HALF_OPTION { add_option(HALF_OPTION); }
;
atomic_operation_spec: ATOMIC_AND { add_option(ATOMIC_AND); }
diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc
index cd925a5..db915fe 100644
--- a/src/cuda-sim/ptx_ir.cc
+++ b/src/cuda-sim/ptx_ir.cc
@@ -118,10 +118,10 @@ symbol_table::symbol_table( const char *scope_name, unsigned entry_point, symbol
{
m_scope_name = std::string(scope_name);
m_reg_allocator=0;
- m_shared_next = 0x100; // for debug with valgrind: make zero imply undefined address
- m_const_next = 0x100; // for debug with valgrind: make zero imply undefined address
- m_global_next = 0x100; // for debug with valgrind: make zero imply undefined address
- m_local_next = 0x100; // for debug with valgrind: make zero imply undefined address
+ m_shared_next = 0x100;
+ m_const_next = 0x100;
+ m_global_next = 0x100;
+ m_local_next = 0;
m_parent = parent;
if ( m_parent ) {
m_shared_next = m_parent->m_shared_next;
@@ -140,12 +140,24 @@ const ptx_version &symbol_table::get_ptx_version() const
else return m_parent->get_ptx_version();
}
+unsigned symbol_table::get_sm_target() const
+{
+ if( m_parent == NULL )
+ return m_ptx_version.target();
+ else return m_parent->get_sm_target();
+}
+
void symbol_table::set_ptx_version( float ver, unsigned ext )
{
m_ptx_version = ptx_version(ver,ext);
assert( m_ptx_version.ver() < 3 );
}
+void symbol_table::set_sm_target( const char *target, const char *ext, const char *ext2 )
+{
+ m_ptx_version.set_target(target,ext,ext2);
+}
+
symbol *symbol_table::lookup( const char *identifier )
{
std::string key(identifier);
@@ -306,13 +318,13 @@ void function_info::create_basic_blocks()
i = find_next_real_instruction(++i);
} else {
switch( pI->get_opcode() ) {
- case BRA_OP: case RET_OP: case EXIT_OP:
+ case BRA_OP: case RET_OP: case EXIT_OP: case RETP_OP:
i++;
if( i != m_instructions.end() )
leaders.push_back(*i);
i = find_next_real_instruction(i);
break;
- case CALL_OP:
+ case CALL_OP: case CALLP_OP:
if( pI->has_pred() ) {
printf("GPGPU-Sim PTX: Warning found predicated call\n");
i++;
@@ -424,7 +436,7 @@ void function_info::connect_basic_blocks( ) //iterate across m_basic_blocks of f
ptx_instruction *pI = (*bb_itr)->ptx_end;
if ((*bb_itr)->is_exit) //reached last basic block, no successors to link
continue;
- if (pI->get_opcode() == RET_OP || pI->get_opcode() == EXIT_OP ) {
+ if (pI->get_opcode() == RETP_OP || pI->get_opcode() == RET_OP || pI->get_opcode() == EXIT_OP ) {
(*bb_itr)->successor_ids.insert(exit_bb->bb_id);
exit_bb->predecessor_ids.insert((*bb_itr)->bb_id);
if( pI->has_pred() ) {
@@ -451,7 +463,7 @@ void function_info::connect_basic_blocks( ) //iterate across m_basic_blocks of f
// if basic block does not end in an unpredicated branch,
// then next basic block is also successor
// (this is better than testing for .uni)
- unsigned next_addr = pI->get_m_instr_mem_index() + 1;
+ unsigned next_addr = pI->get_m_instr_mem_index() + pI->inst_size();
basic_block_t *next_bb = m_instr_mem[next_addr]->get_bb();
(*bb_itr)->successor_ids.insert(next_bb->bb_id);
next_bb->predecessor_ids.insert((*bb_itr)->bb_id);
@@ -653,12 +665,12 @@ void function_info::find_ipostdominators( )
void function_info::find_idominators( )
{
- // find immediate postdominator blocks, using algorithm of
+ // find immediate dominator blocks, using algorithm of
// Muchnick's Adv. Compiler Design & Implemmntation Fig 7.15
- printf("GPGPU-Sim PTX: Finding immediate postdominators for \'%s\'...\n", m_name.c_str() );
+ printf("GPGPU-Sim PTX: Finding immediate dominators for \'%s\'...\n", m_name.c_str() );
fflush(stdout);
- assert( m_basic_blocks.size() >= 2 ); // must have a distinquished exit block
- for (unsigned i=0; i<m_basic_blocks.size(); i++) { //initialize Tmp(n) to all pdoms of n except for n
+ assert( m_basic_blocks.size() >= 2 ); // must have a distinquished entry block
+ for (unsigned i=0; i<m_basic_blocks.size(); i++) { //initialize Tmp(n) to all doms of n except for n
m_basic_blocks[i]->Tmp_ids = m_basic_blocks[i]->dominator_ids;
assert( m_basic_blocks[i]->bb_id == i );
m_basic_blocks[i]->Tmp_ids.erase(i);
@@ -683,9 +695,9 @@ void function_info::find_idominators( )
unsigned num_idoms=0;
unsigned num_nopred = 0;
for ( int n = 0; n < m_basic_blocks.size(); ++n) {
- assert( m_basic_blocks[n]->Tmp_ids.size() <= 1 );
- // if the above assert fails we have an error in either postdominator
- // computation, the flow graph does not have a unique exit, or some other error
+ //assert( m_basic_blocks[n]->Tmp_ids.size() <= 1 );
+ // if the above assert fails we have an error in either dominator
+ // computation, the flow graph does not have a unique entry, or some other error
if( !m_basic_blocks[n]->Tmp_ids.empty() ) {
m_basic_blocks[n]->immediatedominator_id = *m_basic_blocks[n]->Tmp_ids.begin();
num_idoms++;
@@ -843,6 +855,8 @@ unsigned type_info_key::type_decode( int type, size_t &size, int &basic_type )
case B16_TYPE: size=16; basic_type=0; return 13;
case B32_TYPE: size=32; basic_type=0; return 14;
case B64_TYPE: size=64; basic_type=0; return 15;
+ case BB64_TYPE: size=64; basic_type=0; return 15;
+ case BB128_TYPE: size=128; basic_type=0; return 16;
case TEXREF_TYPE: case SAMPLERREF_TYPE: case SURFREF_TYPE:
size=32; basic_type=3; return 16;
default:
@@ -968,7 +982,8 @@ ptx_instruction::ptx_instruction( int opcode,
memory_space_t space_spec,
const char *file,
unsigned line,
- const char *source )
+ const char *source,
+ unsigned warp_size ) : inst_t()
{
m_uid = ++g_num_ptx_inst_uid;
m_PC = 0;
@@ -996,8 +1011,9 @@ ptx_instruction::ptx_instruction( int opcode,
m_geom_spec = 0;
m_vector_spec = 0;
m_atomic_spec = 0;
- m_warp_size = ::warp_size;
+ m_warp_size = warp_size;
m_membar_level = 0;
+ m_inst_size = 8; // bytes
std::list<int>::const_iterator i;
unsigned n=1;
@@ -1096,6 +1112,9 @@ ptx_instruction::ptx_instruction( int opcode,
case CTA_OPTION:
m_membar_level = CTA_OPTION;
break;
+ case SYS_OPTION:
+ m_membar_level = SYS_OPTION;
+ break;
case FTZ_OPTION:
break;
case EXIT_OPTION:
@@ -1113,7 +1132,9 @@ ptx_instruction::ptx_instruction( int opcode,
case CA_OPTION: case CG_OPTION: case CS_OPTION: case LU_OPTION: case CV_OPTION:
m_cache_option = last_ptx_inst_option;
break;
-
+ case HALF_OPTION:
+ m_inst_size = 4; // bytes
+ break;
default:
assert(0);
break;
@@ -1141,7 +1162,7 @@ void ptx_instruction::print_insn( FILE *fp ) const
snprintf(buf,1024,"%s", m_source.c_str());
p = strtok(buf,";");
if( !is_label() )
- fprintf(fp,"PC=%3u [idx=%3u] ", m_PC, m_instr_mem_index );
+ fprintf(fp," PC=%3u [%3u] ", m_PC, m_instr_mem_index );
else
fprintf(fp," " );
fprintf(fp,"(%s:%u) %s", m_source_file.c_str(), m_source_line, p );
@@ -1168,7 +1189,13 @@ function_info::function_info(int entry_point )
void function_info::print_insn( unsigned pc, FILE * fp ) const
{
unsigned index = pc - m_start_PC;
- fprintf(fp,"FUNC[%s]",m_name.c_str() );
+ char command[1024];
+ char buffer[1024];
+ snprintf(command,1024,"c++filt -p %s",m_name.c_str());
+ FILE *p = popen(command,"r");
+ buffer[0]=0;
+ fscanf(p,"%1023s",buffer);
+ fprintf(fp,"%s",buffer);
if ( index >= m_instr_mem_size ) {
fprintf(fp, "<past last instruction (max pc=%u)>", m_start_PC + m_instr_mem_size - 1 );
} else {
@@ -1191,10 +1218,13 @@ extern "C" FILE *ptxinfo_in;
void gpgpu_ptx_assemble( std::string kname, void *kinfo )
{
function_info *func_info = (function_info *)kinfo;
+ if((function_info *)kinfo == NULL) {
+ printf("GPGPU-Sim PTX: Error - missing function definition \'%s\'\n", kname.c_str());
+ abort();
+ }
if( func_info->is_extern() ) {
printf("GPGPU-Sim PTX: skipping assembly for extern declared function \'%s\'\n", func_info->get_name().c_str() );
return;
}
- g_func_info = func_info;
func_info->ptx_assemble();
}
diff --git a/src/cuda-sim/ptx_ir.h b/src/cuda-sim/ptx_ir.h
index 43ac92a..afb2476 100644
--- a/src/cuda-sim/ptx_ir.h
+++ b/src/cuda-sim/ptx_ir.h
@@ -319,7 +319,9 @@ public:
symbol_table( const char *scope_name, unsigned entry_point, symbol_table *parent );
void set_name( const char *name );
const ptx_version &get_ptx_version() const;
+ unsigned get_sm_target() const;
void set_ptx_version( float ver, unsigned ext );
+ void set_sm_target( const char *target, const char *ext, const char *ext2 );
symbol* lookup( const char *identifier );
std::string get_scope_name() const { return m_scope_name; }
symbol *add_variable( const char *identifier, const type_info *type, unsigned size, const char *filename, unsigned line );
@@ -784,9 +786,9 @@ struct gpgpu_recon_t {
address_type target_pc;
};
-class ptx_instruction {
+class ptx_instruction : public inst_t {
public:
- ptx_instruction( int opcode,
+ ptx_instruction( int opcode,
const symbol *pred,
int neg_pred,
int pred_mod,
@@ -798,9 +800,13 @@ public:
memory_space_t space_spec,
const char *file,
unsigned line,
- const char *source );
+ const char *source,
+ unsigned warp_size );
+
+
void print_insn() const;
- void print_insn( FILE *fp ) const;
+ virtual void print_insn( FILE *fp ) const;
+ unsigned inst_size() const { return m_inst_size; }
unsigned uid() const { return m_uid;}
int get_opcode() const { return m_opcode;}
const char *get_opcode_cstr() const
@@ -961,6 +967,7 @@ public:
}
private:
+
basic_block_t *m_basic_block;
unsigned m_uid;
addr_t m_PC;
@@ -999,6 +1006,10 @@ private:
enum vote_mode_t m_vote_mode;
int m_membar_level;
int m_instr_mem_index; //index into m_instr_mem array
+ unsigned m_inst_size; // bytes
+
+ virtual void pre_decode();
+ friend class function_info;
};
class param_info {
@@ -1036,6 +1047,7 @@ class function_info {
public:
function_info(int entry_point );
const ptx_version &get_ptx_version() const { return m_symtab->get_ptx_version(); }
+ unsigned get_sm_target() const { return m_symtab->get_sm_target(); }
bool is_extern() const { return m_extern; }
void set_name(const char *name)
{
@@ -1094,22 +1106,7 @@ public:
unsigned get_function_size() { return m_instructions.size();}
void ptx_assemble();
- void ptx_decode_inst( ptx_thread_info *thd,
- unsigned *op_type,
- int *i1,
- int *i2,
- int *i3,
- int *i4,
- int *o1,
- int *o2,
- int *o3,
- int *o4,
- int *vectorin,
- int *vectorout,
- int *arch_reg,
- int *pred,
- int *ar1, int *ar2 );
- void ptx_exec_inst( ptx_thread_info *thd, addr_t *addr, memory_space_t *space, unsigned *data_size, unsigned *cycles, dram_callback_t* callback, unsigned warp_active_mask );
+
unsigned ptx_get_inst_op( ptx_thread_info *thread );
void add_param( const char *name, struct param_t value )
{
@@ -1169,6 +1166,8 @@ public:
const void set_kernel_info (const struct gpgpu_ptx_sim_kernel_info &info) {
m_kernel_info = info;
+ m_kernel_info.ptx_version = 10*get_ptx_version().ver();
+ m_kernel_info.sm_target = get_ptx_version().target();
}
symbol_table *get_symtab()
{
@@ -1177,9 +1176,8 @@ public:
static const ptx_instruction* pc_to_instruction(unsigned pc)
{
- assert(pc > 0);
assert(pc <= s_g_pc_to_insn.size());
- return s_g_pc_to_insn[pc - 1];
+ return s_g_pc_to_insn[pc];
}
unsigned local_mem_framesize() const
{
@@ -1404,16 +1402,12 @@ struct textureInfo {
unsigned int texel_size_numbits; //log2(texel_size)
};
-
-extern function_info *g_func_info;
-
-extern function_info *g_entrypoint_func_info;
extern std::map<std::string,symbol_table*> g_sym_name_to_symbol_table;
-#define GLOBAL_HEAP_START 0x10000000
+#define GLOBAL_HEAP_START 0x80000000
// start allocating from this address (lower values used for allocating globals in .ptx file)
#define SHARED_MEM_SIZE_MAX (64*1024)
-#define LOCAL_MEM_SIZE_MAX 1024
+#define LOCAL_MEM_SIZE_MAX (16*1024)
#define MAX_STREAMING_MULTIPROCESSORS 64
#define MAX_THREAD_PER_SM 1024
#define TOTAL_LOCAL_MEM_PER_SM (MAX_THREAD_PER_SM*LOCAL_MEM_SIZE_MAX)
diff --git a/src/cuda-sim/ptx_loader.cc b/src/cuda-sim/ptx_loader.cc
index 783ce91..1aa5101 100644
--- a/src/cuda-sim/ptx_loader.cc
+++ b/src/cuda-sim/ptx_loader.cc
@@ -67,6 +67,7 @@
#include "cuda-sim.h"
#include "ptx_parser.h"
#include <dirent.h>
+#include <fstream>
/// globals
@@ -78,6 +79,7 @@ bool g_override_embedded_ptx = false;
struct ptx_info_t {
char *str;
+ char *cubin_str;
char *fname;
ptx_info_t *next;
};
@@ -93,6 +95,9 @@ extern "C" int ptxinfo_parse();
extern "C" int ptxinfo_debug;
extern "C" FILE *ptxinfo_in;
+extern int g_ptx_convert_to_ptxplus;
+extern int g_ptx_save_converted_ptxplus;
+
/// static functions
static int load_static_globals( symbol_table *symtab, unsigned min_gaddr, unsigned max_gaddr)
@@ -223,11 +228,23 @@ void gpgpu_ptx_sim_load_gpu_kernels()
printf("GPGPU-Sim PTX: USING EMBEDDED .ptx files...\n");
ptx_info_t *s;
for ( s=g_ptx_source_array; s!=NULL; s=s->next ) {
- symbol_table *symtab=gpgpu_ptx_sim_load_ptx_from_string(s->str, ++source_num);
+ symbol_table *symtab;
+ source_num++;
+ if(g_ptx_convert_to_ptxplus) {
+ char *ptxplus_str = gpgpu_ptx_sim_convert_ptx_to_ptxplus(s->str, s->cubin_str, source_num);
+ symtab=gpgpu_ptx_sim_load_ptx_from_string(ptxplus_str, s->str, source_num);
+ delete[] ptxplus_str;
+ } else {
+ symtab=gpgpu_ptx_sim_load_ptx_from_string(s->str, s->str, source_num);
+ }
load_static_globals(symtab,STATIC_ALLOC_LIMIT,0xFFFFFFFF);
load_constants(symtab,STATIC_ALLOC_LIMIT);
}
} else {
+ if(g_ptx_convert_to_ptxplus) {
+ perror("GPGPU-Sim PTX: convert_to_ptxplus option enabled. Cannot use this option with external ptx files.\n");
+ assert(0);
+ }
const char *filename = NULL;
struct dirent **namelist;
int n = scandir(".", &namelist, ptx_file_filter, alphasort);
@@ -235,20 +252,17 @@ void gpgpu_ptx_sim_load_gpu_kernels()
perror("GPGPU-Sim PTX: no PTX files returned by scandir");
else {
while (n--) {
- if ( filename != NULL ) {
- printf("Loader error: support for multiple .ptx files not yet enabled\n");
- abort();
- }
filename = namelist[n]->d_name;
printf("Parsing %s..\n", filename);
ptx_in = fopen( filename, "r" );
- free(namelist[n]);
symbol_table *symtab=init_parser(filename);
ptx_parse ();
ptxinfo_in = open_ptxinfo(filename);
ptxinfo_parse();
load_static_globals(symtab,STATIC_ALLOC_LIMIT,0xFFFFFFFF);
load_constants(symtab,STATIC_ALLOC_LIMIT);
+
+ free(namelist[n]);
}
free(namelist);
}
@@ -278,11 +292,17 @@ void gpgpu_ptx_sim_load_gpu_kernels()
}
}
-void gpgpu_ptx_sim_add_ptxstring( const char *ptx_string, const char *sourcefname )
+void gpgpu_ptx_sim_add_ptxstring( const char *ptx_string, const char *cubin_string, const char *sourcefname )
{
ptx_info_t *t = new ptx_info_t;
t->next = NULL;
t->str = strdup(ptx_string);
+ if (cubin_string != NULL) {
+ t->cubin_str = strdup(cubin_string);
+ } else {
+ assert(g_ptx_convert_to_ptxplus == 0);
+ t->cubin_str = NULL;
+ }
t->fname = strdup(sourcefname);
// put ptx source into a fifo
@@ -338,7 +358,106 @@ void print_ptx_file( const char *p, unsigned source_num, const char *filename )
fflush(stdout);
}
-symbol_table *gpgpu_ptx_sim_load_ptx_from_string( const char *p, unsigned source_num )
+char* gpgpu_ptx_sim_convert_ptx_to_ptxplus(const char *ptx_str, const char *cubin_str, unsigned source_num)
+{
+ printf("GPGPU-Sim PTX: converting EMBEDDED .ptx file to ptxplus \n");
+
+ // Extract ptx to a file
+ char fname_ptx[1024];
+ snprintf(fname_ptx,1024,"_ptx_XXXXXX");
+ int fd=mkstemp(fname_ptx);
+ close(fd);
+
+ printf("GPGPU-Sim PTX: extracting embedded .ptx to temporary file \"%s\"\n", fname_ptx);
+ FILE *ptxfile = fopen(fname_ptx,"w");
+ fprintf(ptxfile,"%s",ptx_str);
+ fclose(ptxfile);
+
+ // Extract cubin to a file
+ char fname_cubin[1024];
+ snprintf(fname_cubin,1024,"_cubin_XXXXXX");
+ int fd2=mkstemp(fname_cubin);
+ close(fd2);
+
+ printf("GPGPU-Sim PTX: extracting embedded cubin to temporary file \"%s\"\n", fname_cubin);
+ FILE *cubinfile = fopen(fname_cubin,"w");
+ fprintf(cubinfile,"%s",cubin_str);
+ fclose(cubinfile);
+
+ // Run decuda
+ char fname_decuda[1024];
+ snprintf(fname_decuda,1024,"_decuda_XXXXXX");
+ int fd3=mkstemp(fname_decuda);
+ close(fd3);
+
+ char decuda_commandline[1024];
+ snprintf(decuda_commandline,1024,"$DECUDA_INSTALL_PATH/decuda.py -o %s %s", fname_decuda, fname_cubin);
+
+ printf("GPGPU-Sim PTX: calling decuda on cubin file, decuda output file = \"%s\"\n", fname_decuda);
+ int decuda_result = system(decuda_commandline);
+ if( decuda_result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while calling decuda (b) %d\n", decuda_result);
+ printf(" Ensure env variable DECUDA_INSTALL_PATH is set and points to decuda base directory.\n");
+ exit(1);
+ }
+
+ // Run decuda_to_ptxplus
+ char fname_ptxplus[1024];
+ snprintf(fname_ptxplus,1024,"_ptxplus_XXXXXX");
+ int fd4=mkstemp(fname_ptxplus);
+ close(fd4);
+
+ char d2pp_commandline[1024];
+ snprintf(d2pp_commandline,1024,"$D2PP_INSTALL_PATH/decuda_to_ptxplus %s %s %s %s > /dev/null", fname_decuda, fname_ptx, fname_cubin, fname_ptxplus);
+
+ printf("GPGPU-Sim PTX: calling decuda_to_ptxplus, ptxplus output file = \"%s\"\n", fname_ptxplus);
+ int d2pp_result = system(d2pp_commandline);
+ if( d2pp_result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while calling decuda_to_ptxplus %d\n", d2pp_result);
+ printf(" Ensure env variable D2PP_INSTALL_PATH is set and points to decuda_to_ptxplus base directory.\n");
+ exit(1);
+ }
+
+ // Get ptxplus from file
+ std::ifstream fileStream(fname_ptxplus, std::ios::in);
+ std::string text, line;
+ while(getline(fileStream,line)) {
+ text += (line + "\n");
+ }
+ fileStream.close();
+
+ char* ptxplus_str = new char [strlen(text.c_str())+1];
+ strcpy(ptxplus_str, text.c_str());
+
+ // Save ptxplus to file if specified
+ if(g_ptx_save_converted_ptxplus) {
+ char fname_ptxplus_save[1024];
+ snprintf(fname_ptxplus_save,1024,"_%u.ptxplus", source_num );
+ printf("GPGPU-Sim PTX: saving converted ptxplus to file \"%s\"\n", fname_ptxplus_save);
+
+ FILE *file_ptxplus_save = fopen(fname_ptxplus_save,"w");
+ fprintf(file_ptxplus_save,"%s",ptxplus_str);
+ fclose(file_ptxplus_save);
+ }
+
+ // Remove temporary files
+ char rm_commandline[1024];
+ snprintf(rm_commandline,1024,"rm -f %s %s %s %s", fname_ptx, fname_cubin, fname_decuda, fname_ptxplus);
+ printf("GPGPU-Sim PTX: removing temporary files using \"%s\"\n", rm_commandline);
+ int rm_result = system(rm_commandline);
+ if( rm_result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while removing temporary files %d\n", rm_result);
+ exit(1);
+ }
+
+ printf("GPGPU-Sim PTX: DONE converting EMBEDDED .ptx file to ptxplus \n");
+
+ return ptxplus_str;
+
+}
+
+
+symbol_table *gpgpu_ptx_sim_load_ptx_from_string( const char *p, const char *p_for_info, unsigned source_num )
{
char buf[1024];
snprintf(buf,1024,"_%u.ptx", source_num );
@@ -375,7 +494,7 @@ symbol_table *gpgpu_ptx_sim_load_ptx_from_string( const char *p, unsigned source
printf("GPGPU-Sim PTX: extracting embedded .ptx to temporary file \"%s\"\n", fname);
FILE *ptxfile = fopen(fname,"w");
- fprintf(ptxfile,"%s",p);
+ fprintf(ptxfile,"%s", p_for_info);
fclose(ptxfile);
char fname2[1024];
diff --git a/src/cuda-sim/ptx_loader.h b/src/cuda-sim/ptx_loader.h
index 95130f1..01dc0b7 100644
--- a/src/cuda-sim/ptx_loader.h
+++ b/src/cuda-sim/ptx_loader.h
@@ -75,7 +75,8 @@ extern memory_space *g_param_mem;
extern bool g_override_embedded_ptx;
void gpgpu_ptx_sim_load_gpu_kernels();
-void gpgpu_ptx_sim_add_ptxstring( const char *ptx_string, const char *sourcefname );
-class symbol_table *gpgpu_ptx_sim_load_ptx_from_string( const char *p, unsigned source_num );
+void gpgpu_ptx_sim_add_ptxstring( const char *ptx_string, const char *cubin_string, const char *sourcefname );
+class symbol_table *gpgpu_ptx_sim_load_ptx_from_string( const char *p, const char *p_for_info, unsigned source_num );
+char* gpgpu_ptx_sim_convert_ptx_to_ptxplus(const char *ptx_str, const char *cubin_str, unsigned source_num);
#endif
diff --git a/src/cuda-sim/ptx_parser.cc b/src/cuda-sim/ptx_parser.cc
index d4a892f..5a65481 100644
--- a/src/cuda-sim/ptx_parser.cc
+++ b/src/cuda-sim/ptx_parser.cc
@@ -68,6 +68,12 @@
extern "C" int ptx_error( const char *s );
extern int ptx_lineno;
+static unsigned g_warp_size;
+void set_ptx_warp_size(unsigned warp_size)
+{
+ g_warp_size=warp_size;
+}
+
static bool g_debug_ir_generation=false;
const char *g_filename;
unsigned g_max_regs_per_thread = 0;
@@ -110,12 +116,10 @@ std::list<int> g_scalar_type;
fflush(stdout); \
}
-unsigned g_entry_func_param_index=0;
-function_info *g_func_info = NULL;
-function_info *g_entrypoint_func_info = NULL;
-symbol_table *g_entrypoint_symbol_table = NULL;
-std::map<unsigned,std::string> g_ptx_token_decode;
-operand_info g_return_var;
+static unsigned g_entry_func_param_index=0;
+static function_info *g_func_info = NULL;
+static std::map<unsigned,std::string> g_ptx_token_decode;
+static operand_info g_return_var;
const char *decode_token( int type )
{
@@ -194,9 +198,6 @@ void add_function_name( const char *name )
{
DPRINTF("add_function_name %s %s", name, ((g_entry_point==1)?"(entrypoint)":((g_entry_point==2)?"(extern)":"")));
bool prior_decl = g_global_symbol_table->add_function_decl( name, g_entry_point, &g_func_info, &g_current_symbol_table );
- if( g_entry_point ) {
- g_entrypoint_func_info = g_func_info;
- }
if( g_add_identifier_cached__identifier ) {
add_identifier( g_add_identifier_cached__identifier,
g_add_identifier_cached__array_dim,
@@ -270,7 +271,7 @@ extern "C" char linebuf[1024];
void set_return()
{
- parse_assert( (g_opcode == CALL_OP), "only call can have return value");
+ parse_assert( (g_opcode == CALL_OP || g_opcode == CALLP_OP), "only call can have return value");
g_operands.front().set_return();
g_return_var = g_operands.front();
}
@@ -291,6 +292,7 @@ const ptx_instruction *ptx_instruction_lookup( const char *filename, unsigned li
void add_instruction()
{
DPRINTF("add_instruction: %s", ((g_opcode>0)?g_opcode_string[g_opcode]:"<label>") );
+ assert( g_warp_size != 0 );
ptx_instruction *i = new ptx_instruction( g_opcode,
g_pred,
g_neg_pred,
@@ -303,7 +305,8 @@ void add_instruction()
g_space_spec,
g_filename,
ptx_lineno,
- linebuf );
+ linebuf,
+ g_warp_size );
g_instructions.push_back(i);
g_inst_lookup[g_filename][ptx_lineno] = i;
init_instruction_state();
@@ -457,7 +460,14 @@ void add_identifier( const char *identifier, int array_dim, unsigned array_ident
break;
case local_space:
if( g_func_info == NULL ) {
- printf("GPGPU-Sim PTX: not allocating .local \"%s\" declared at global scope\n", identifier);
+ printf("GPGPU-Sim PTX: allocating local region for \"%s\" from 0x%x to 0x%lx (local memory space)\n",
+ identifier,
+ g_current_symbol_table->get_local_next(),
+ g_current_symbol_table->get_local_next() + num_bits/8 );
+ fflush(stdout);
+ assert( (num_bits%8) == 0 );
+ g_last_symbol->set_address( g_current_symbol_table->get_local_next() );
+ g_current_symbol_table->alloc_local( num_bits/8 );
break;
}
printf("GPGPU-Sim PTX: allocating stack frame region for .local \"%s\" from 0x%x to 0x%lx\n",
@@ -647,6 +657,10 @@ void add_4vector_operand( const char *d1, const char *d2, const char *d3, const
const symbol *s3 = g_current_symbol_table->lookup(d3);
const symbol *s4 = g_current_symbol_table->lookup(d4);
parse_assert( s1 != NULL && s2 != NULL && s3 != NULL && s4 != NULL, "v4 component(s) missing declarations.");
+ const symbol *null_op = g_current_symbol_table->lookup("_");
+ if ( s2 == null_op ) s2 = NULL;
+ if ( s3 == null_op ) s3 = NULL;
+ if ( s4 == null_op ) s4 = NULL;
g_operands.push_back( operand_info(s1,s2,s3,s4) );
}
@@ -789,7 +803,7 @@ void add_scalar_operand( const char *identifier )
DPRINTF("add_scalar_operand");
const symbol *s = g_current_symbol_table->lookup(identifier);
if ( s == NULL ) {
- if ( g_opcode == BRA_OP ) {
+ if ( g_opcode == BRA_OP || g_opcode == CALLP_OP) {
// forward branch target...
s = g_current_symbol_table->add_variable(identifier,NULL,0,g_filename,ptx_lineno);
} else {
@@ -828,9 +842,9 @@ void add_array_initializer()
g_last_symbol->add_initializer(g_operands);
}
-void add_version_info( float ver )
+void add_version_info( float ver, unsigned ext )
{
- g_global_symbol_table->set_ptx_version(ver,0);
+ g_global_symbol_table->set_ptx_version(ver,ext);
}
void add_file( unsigned num, const char *filename )
@@ -878,8 +892,21 @@ void add_pragma( const char *str )
}
void version_header(double a) {} //intentional dummy function
-void target_header(char* a) {} //intentional dummy function
-void target_header2(char* a, char* b) {} //intentional dummy function
+
+void target_header(char* a)
+{
+ g_global_symbol_table->set_sm_target(a,NULL,NULL);
+}
+
+void target_header2(char* a, char* b)
+{
+ g_global_symbol_table->set_sm_target(a,b,NULL);
+}
+
+void target_header3(char* a, char* b, char* c)
+{
+ g_global_symbol_table->set_sm_target(a,b,c);
+}
void func_header(char* a) {} //intentional dummy function
void func_header_info(char* a) {} //intentional dummy function
diff --git a/src/cuda-sim/ptx_parser.h b/src/cuda-sim/ptx_parser.h
index 4852e39..dba88ca 100644
--- a/src/cuda-sim/ptx_parser.h
+++ b/src/cuda-sim/ptx_parser.h
@@ -110,7 +110,7 @@ void set_return();
void add_alignment_spec( int spec );
void add_array_initializer();
void add_file( unsigned num, const char *filename );
-void add_version_info( float ver );
+void add_version_info( float ver, unsigned ext);
void *reset_symtab();
void set_symtab(void*);
void add_pragma( const char *str );
@@ -120,6 +120,7 @@ void func_header_info_int(char* a, int b);
void add_constptr(const char* identifier1, const char* identifier2, int offset);
void target_header(char* a);
void target_header2(char* a, char* b);
+void target_header3(char* a, char* b, char* c);
void add_double_operand( const char *d1, const char *d2 );
void change_memory_addr_space( const char *identifier );
void change_operand_lohi( int lohi );
diff --git a/src/cuda-sim/ptx_sim.cc b/src/cuda-sim/ptx_sim.cc
index 6dea2e3..2cd0ba6 100644
--- a/src/cuda-sim/ptx_sim.cc
+++ b/src/cuda-sim/ptx_sim.cc
@@ -71,7 +71,6 @@ void feature_not_implemented( const char *f );
std::set<unsigned long long> g_ptx_cta_info_sm_idx_used;
unsigned long long g_ptx_cta_info_uid = 1;
-extern int gpgpu_option_spread_blocks_across_cores;
ptx_cta_info::ptx_cta_info( unsigned sm_idx )
{
@@ -276,7 +275,11 @@ unsigned ptx_thread_info::get_builtin( int builtin_id, unsigned dim_mod )
return (gpu_sim_cycle + gpu_tot_sim_cycle)*2;
case CTAID_REG:
assert( dim_mod < 3 );
- return m_ctaid[dim_mod];
+ if( dim_mod == 0 ) return m_ctaid.x;
+ if( dim_mod == 1 ) return m_ctaid.y;
+ if( dim_mod == 2 ) return m_ctaid.z;
+ abort();
+ break;
case ENVREG_REG: feature_not_implemented( "%envreg" ); return 0;
case GRIDID_REG:
return m_gridid;
@@ -288,16 +291,28 @@ unsigned ptx_thread_info::get_builtin( int builtin_id, unsigned dim_mod )
case LANEMASK_GT_REG: feature_not_implemented( "%lanemask_gt" ); return 0;
case NCTAID_REG:
assert( dim_mod < 3 );
- return m_nctaid[dim_mod];
+ if( dim_mod == 0 ) return m_nctaid.x;
+ if( dim_mod == 1 ) return m_nctaid.y;
+ if( dim_mod == 2 ) return m_nctaid.z;
+ abort();
+ break;
case NTID_REG:
assert( dim_mod < 3 );
- return m_ntid[dim_mod];
+ if( dim_mod == 0 ) return m_ntid.x;
+ if( dim_mod == 1 ) return m_ntid.y;
+ if( dim_mod == 2 ) return m_ntid.z;
+ abort();
+ break;
case NWARPID_REG: feature_not_implemented( "%nwarpid" ); return 0;
case PM_REG: feature_not_implemented( "%pm" ); return 0;
case SMID_REG: feature_not_implemented( "%smid" ); return 0;
case TID_REG:
assert( dim_mod < 3 );
- return m_tid[dim_mod];
+ if( dim_mod == 0 ) return m_tid.x;
+ if( dim_mod == 1 ) return m_tid.y;
+ if( dim_mod == 2 ) return m_tid.z;
+ abort();
+ break;
case WARPSZ_REG: feature_not_implemented( "WARP_SZ" ); return 0;
default:
assert(0);
@@ -312,13 +327,13 @@ void ptx_thread_info::set_info( function_info *func )
m_PC = func->get_start_PC();
}
-void ptx_thread_info::cpy_tid_to_reg( int x, int y, int z)
+void ptx_thread_info::cpy_tid_to_reg( dim3 tid )
{
//copies %tid.x, %tid.y and %tid.z into $r0
ptx_reg_t data;
data.s64=0;
- data.u32=(x + (y<<16) + (z<<26));
+ data.u32=(tid.x + (tid.y<<16) + (tid.z<<26));
const symbol *r0 = m_symbol_table->lookup("$r0");
set_reg(r0,data);
@@ -386,6 +401,21 @@ void ptx_thread_info::callstack_push( unsigned pc, unsigned rpc, const symbol *r
m_local_mem_stack_pointer += m_func_info->local_mem_framesize();
}
+//ptxplus version of callstack_push.
+void ptx_thread_info::callstack_push_plus( unsigned pc, unsigned rpc, const symbol *return_var_src, const symbol *return_var_dst, unsigned call_uid )
+{
+ m_RPC = -1;
+ m_RPC_updated = true;
+ m_last_was_call = true;
+ assert( m_func_info != NULL );
+ m_callstack.push_back( stack_entry(m_symbol_table,m_func_info,pc,rpc,return_var_src,return_var_dst,call_uid) );
+ //m_regs.push_back( reg_map_t() );
+ //m_debug_trace_regs_modified.push_back( reg_map_t() );
+ //m_debug_trace_regs_read.push_back( reg_map_t() );
+ m_local_mem_stack_pointer += m_func_info->local_mem_framesize();
+}
+
+
bool ptx_thread_info::callstack_pop()
{
const symbol *rv_src = m_callstack.back().m_return_var_src;
@@ -419,6 +449,40 @@ bool ptx_thread_info::callstack_pop()
return m_callstack.empty();
}
+//ptxplus version of callstack_pop
+bool ptx_thread_info::callstack_pop_plus()
+{
+ const symbol *rv_src = m_callstack.back().m_return_var_src;
+ const symbol *rv_dst = m_callstack.back().m_return_var_dst;
+ assert( !((rv_src != NULL) ^ (rv_dst != NULL)) ); // ensure caller and callee agree on whether there is a return value
+
+ // read return value from callee frame
+ arg_buffer_t buffer;
+ if( rv_src != NULL )
+ buffer = copy_arg_to_buffer(this, operand_info(rv_src), rv_dst );
+
+ m_symbol_table = m_callstack.back().m_symbol_table;
+ m_NPC = m_callstack.back().m_PC;
+ m_RPC_updated = true;
+ m_last_was_call = false;
+ m_RPC = m_callstack.back().m_RPC;
+ m_func_info = m_callstack.back().m_func_info;
+ if( m_func_info ) {
+ assert( m_local_mem_stack_pointer >= m_func_info->local_mem_framesize() );
+ m_local_mem_stack_pointer -= m_func_info->local_mem_framesize();
+ }
+ m_callstack.pop_back();
+ //m_regs.pop_back();
+ //m_debug_trace_regs_modified.pop_back();
+ //m_debug_trace_regs_read.pop_back();
+
+ // write return value into caller frame
+ if( rv_dst != NULL )
+ copy_buffer_to_frame(this, buffer);
+
+ return m_callstack.empty();
+}
+
void ptx_thread_info::dump_callstack() const
{
std::list<stack_entry>::const_iterator c=m_callstack.begin();
@@ -476,7 +540,7 @@ void ptx_thread_info::dump_regs( FILE *fp )
const symbol *sym = r->first;
ptx_reg_t value = r->second;
std::string name = sym->name();
- print_reg(name,value,m_symbol_table);
+ print_reg(fp,name,value,m_symbol_table);
}
}
diff --git a/src/cuda-sim/ptx_sim.h b/src/cuda-sim/ptx_sim.h
index 4741769..3a6d9ad 100644
--- a/src/cuda-sim/ptx_sim.h
+++ b/src/cuda-sim/ptx_sim.h
@@ -71,23 +71,6 @@
#include "../abstract_hardware_model.h"
#include "../tr1_hash_map.h"
-
-struct gpgpu_ptx_sim_arg {
- const void *m_start;
- size_t m_nbytes;
- size_t m_offset;
- struct gpgpu_ptx_sim_arg *m_next;
-};
-
-//Holds properties of the kernel (Kernel's resource use). These will be zero if
-//the ptxinfo file is not present.
-struct gpgpu_ptx_sim_kernel_info {
- int lmem;
- int smem;
- int cmem;
- int regs;
-};
-
#include <assert.h>
#include "opcodes.h"
@@ -240,18 +223,51 @@ public:
m_valid = false;
m_ptx_version = 0;
m_ptx_extensions = 0;
+ m_sm_version_valid=false;
+ m_texmode_unified=true;
+ m_map_f64_to_f32 = true;
}
ptx_version(float ver, unsigned extensions)
{
m_valid = true;
m_ptx_version = ver;
m_ptx_extensions = extensions;
+ m_sm_version_valid=false;
+ m_texmode_unified=true;
+ }
+ void set_target( const char *sm_ver, const char *ext, const char *ext2 )
+ {
+ assert( m_valid );
+ m_sm_version_str = sm_ver;
+ check_target_extension(ext);
+ check_target_extension(ext2);
+ sscanf(sm_ver,"%u",&m_sm_version);
+ m_sm_version_valid=true;
}
- float ver() const { assert(m_valid); return m_ptx_version; }
+ float ver() const { assert(m_valid); return m_ptx_version; }
+ unsigned target() const { assert(m_valid&&m_sm_version_valid); return m_sm_version; }
unsigned extensions() const { assert(m_valid); return m_ptx_extensions; }
private:
+ void check_target_extension( const char *ext )
+ {
+ if( ext ) {
+ if( !strcmp(ext,"texmode_independent") )
+ m_texmode_unified=false;
+ else if( !strcmp(ext,"texmode_unified") )
+ m_texmode_unified=true;
+ else if( !strcmp(ext,"map_f64_to_f32") )
+ m_map_f64_to_f32 = true;
+ else abort();
+ }
+ }
+
bool m_valid;
float m_ptx_version;
+ unsigned m_sm_version_valid;
+ std::string m_sm_version_str;
+ bool m_texmode_unified;
+ bool m_map_f64_to_f32;
+ unsigned m_sm_version;
unsigned m_ptx_extensions;
};
@@ -260,6 +276,9 @@ public:
~ptx_thread_info();
ptx_thread_info();
+ void ptx_fetch_inst( inst_t &inst ) const;
+ void ptx_exec_inst( inst_t &inst );
+
const ptx_version &get_ptx_version() const;
void set_reg( const symbol *reg, const ptx_reg_t &value );
ptx_reg_t get_reg( const symbol *reg );
@@ -271,8 +290,7 @@ public:
const ptx_reg_t &data1,
const ptx_reg_t &data2,
const ptx_reg_t &data3,
- const ptx_reg_t &data4,
- unsigned num_elements );
+ const ptx_reg_t &data4 );
function_info *func_info()
{
@@ -285,22 +303,9 @@ public:
return m_uid;
}
- dim3 get_ctaid() const
- {
- dim3 r;
- r.x = m_ctaid[0];
- r.y = m_ctaid[1];
- r.z = m_ctaid[2];
- return r;
- }
- dim3 get_tid() const
- {
- dim3 r;
- r.x = m_tid[0];
- r.y = m_tid[1];
- r.z = m_tid[2];
- return r;
- }
+ dim3 get_ctaid() const { return m_ctaid; }
+ dim3 get_tid() const { return m_tid; }
+ class gpgpu_sim *get_gpu() { return m_core->get_gpu(); }
unsigned get_hw_tid() const { return m_hw_tid;}
unsigned get_hw_ctaid() const { return m_hw_ctaid;}
unsigned get_hw_wid() const { return m_hw_wid;}
@@ -335,46 +340,26 @@ public:
void set_single_thread_single_block()
{
- m_ntid[0] = 1;
- m_ntid[1] = 1;
- m_ntid[2] = 1;
- m_ctaid[0] = 0;
- m_ctaid[1] = 0;
- m_ctaid[2] = 0;
- m_tid[0] = 0;
- m_tid[1] = 0;
- m_tid[2] = 0;
- m_nctaid[0] = 1;
- m_nctaid[1] = 1;
- m_nctaid[2] = 1;
+ m_ntid.x = 1;
+ m_ntid.y = 1;
+ m_ntid.z = 1;
+ m_ctaid.x = 0;
+ m_ctaid.y = 0;
+ m_ctaid.z = 0;
+ m_tid.x = 0;
+ m_tid.y = 0;
+ m_tid.z = 0;
+ m_nctaid.x = 1;
+ m_nctaid.y = 1;
+ m_nctaid.z = 1;
m_gridid = 0;
m_valid = true;
}
- void set_tid( int x, int y, int z)
- {
- m_tid[0] = x;
- m_tid[1] = y;
- m_tid[2] = z;
- }
- void cpy_tid_to_reg( int x, int y, int z);
- void set_ctaid( int x, int y, int z)
- {
- m_ctaid[0] = x;
- m_ctaid[1] = y;
- m_ctaid[2] = z;
- }
- void set_ntid( int x, int y, int z)
- {
- m_ntid[0] = x;
- m_ntid[1] = y;
- m_ntid[2] = z;
- }
- void set_nctaid( int x, int y, int z)
- {
- m_nctaid[0] = x;
- m_nctaid[1] = y;
- m_nctaid[2] = z;
- }
+ void set_tid( dim3 tid ) { m_tid = tid; }
+ void cpy_tid_to_reg( dim3 tid );
+ void set_ctaid( dim3 ctaid ) { m_ctaid = ctaid; }
+ void set_ntid( dim3 tid ) { m_ntid = tid; }
+ void set_nctaid( dim3 cta_size ) { m_nctaid = cta_size; }
unsigned get_builtin( int builtin_id, unsigned dim_mod );
@@ -384,7 +369,6 @@ public:
unsigned next_instr()
{
- m_NPC = m_PC+1; // increment to next instruction in case of no branch
m_icount++;
m_branch_taken = false;
return m_PC;
@@ -404,6 +388,8 @@ public:
void set_npc( const function_info *f );
void callstack_push( unsigned npc, unsigned rpc, const symbol *return_var_src, const symbol *return_var_dst, unsigned call_uid );
bool callstack_pop();
+ void callstack_push_plus( unsigned npc, unsigned rpc, const symbol *return_var_src, const symbol *return_var_dst, unsigned call_uid );
+ bool callstack_pop_plus();
void dump_callstack() const;
std::string get_location() const;
const ptx_instruction *get_inst() const;
@@ -421,7 +407,7 @@ public:
{
return m_callstack.back().m_PC;
}
- void update_pc()
+ void update_pc( unsigned nbytes )
{
m_PC = m_NPC;
}
@@ -451,10 +437,10 @@ private:
unsigned m_uid;
core_t *m_core;
bool m_valid;
- unsigned m_ntid[3];
- unsigned m_tid[3];
- unsigned m_nctaid[3];
- unsigned m_ctaid[3];
+ dim3 m_ntid;
+ dim3 m_tid;
+ dim3 m_nctaid;
+ dim3 m_ctaid;
unsigned m_gridid;
bool m_thread_done;
unsigned m_hw_sid;
diff --git a/src/debug.cc b/src/debug.cc
index 1f5388b..f3febfb 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -37,7 +37,9 @@ void hit_watchpoint( unsigned watchpoint_num, ptx_thread_info *thd, const ptx_in
/// interactive debugger
-void gpgpu_debug()
+extern gpgpu_sim g_the_gpu;
+
+void gpgpu_sim::gpgpu_debug()
{
bool done=true;
@@ -81,14 +83,16 @@ void gpgpu_debug()
done = false;
}
} else {
- for( unsigned sid=0; sid < gpu_n_shader; sid++ ) {
- inst_t *fvi = first_valid_thread(sc[sid]->pipeline_reg[IF_ID]);
+ for( unsigned sid=0; sid < m_n_shader; sid++ ) {
+ inst_t *fvi = m_sc[sid]->first_valid_thread(IF_ID);
if( !fvi ) continue;
- if( thread_at_brkpt(fvi->ptx_thd_info, b) ) {
+ unsigned hw_thread_id = fvi->hw_thread_id;
+ 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 );
- brk_thd = (ptx_thread_info*)fvi->ptx_thd_info;
+ brk_thd = thread;
brk_inst = brk_thd->get_inst();
printf( "GPGPU-Sim PTX DBG: reached by thread uid=%u, sid=%u, hwtid=%u\n",
brk_thd->get_uid(),brk_thd->get_hw_sid(), brk_thd->get_hw_tid() );
@@ -117,7 +121,7 @@ void gpgpu_debug()
int shader_num = 0;
tok = strtok(NULL," \t\n");
sscanf(tok,"%d",&shader_num);
- dump_pipeline_impl((0x40|0x4|0x1),shader_num,0);
+ dump_pipeline((0x40|0x4|0x1),shader_num,0);
printf("\n");
fflush(stdout);
} else if( !strcmp(tok,"q") || !strcmp(tok,"quit") ) {
@@ -190,9 +194,8 @@ void gpgpu_debug()
}
}
-bool thread_at_brkpt( void *thd, const struct brk_pt &b )
+bool thread_at_brkpt( ptx_thread_info *thread, const struct brk_pt &b )
{
- ptx_thread_info *thread = (ptx_thread_info *) thd;
return b.is_equal(thread->get_location(),thread->get_uid());
}
diff --git a/src/debug.h b/src/debug.h
index a6f2b10..7c123a3 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -60,9 +60,8 @@ extern int gpgpu_ptx_instruction_classification ;
class ptx_thread_info;
class ptx_instruction;
-bool thread_at_brkpt( void *ptx_thd_info, const struct brk_pt &b );
+bool thread_at_brkpt( ptx_thread_info *thd_info, const struct brk_pt &b );
unsigned read_location( addr_t addr );
void hit_watchpoint( unsigned watchpoint_num, ptx_thread_info *thd, const ptx_instruction *pI );
-void gpgpu_debug();
#endif
diff --git a/src/gpgpu-sim/Makefile b/src/gpgpu-sim/Makefile
index 96b1a5c..5451736 100644
--- a/src/gpgpu-sim/Makefile
+++ b/src/gpgpu-sim/Makefile
@@ -78,8 +78,8 @@ endif
ifneq ($(DEBUG),1)
OPTFLAGS += -O3
else
- CXXFLAGS_L2CACHE += -DGLIBCXX_DEBUG_PEDANTIC
- CXXFLAGS += -D_GLIBCXX_DEBUG -DGLIBCXX_DEBUG_PEDANTIC
+ CXXFLAGS_L2CACHE +=
+ CXXFLAGS +=
endif
OPTFLAGS += -g3 -fPIC
@@ -127,7 +127,7 @@ addrdec.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
addrdec.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
addrdec.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
addrdec.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
-addrdec.o: /usr/include/assert.h ../option_parser.h
+addrdec.o: /usr/include/assert.h ../option_parser.h gpu-sim.h
delayqueue.o: delayqueue.h /usr/include/stdio.h /usr/include/features.h
delayqueue.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
delayqueue.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
@@ -141,12 +141,14 @@ delayqueue.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
delayqueue.o: /usr/include/sys/select.h /usr/include/bits/select.h
delayqueue.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
delayqueue.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-delayqueue.o: /usr/include/alloca.h gpu-misc.h ../intersim/statwraper.h
-dram.o: gpu-misc.h dram.h /usr/include/stdio.h /usr/include/features.h
-dram.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-dram.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-dram.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-dram.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h
+delayqueue.o: /usr/include/alloca.h gpu-misc.h gpu-sim.h
+delayqueue.o: ../intersim/statwraper.h
+dram.o: gpu-sim.h gpu-misc.h dram.h /usr/include/stdio.h
+dram.o: /usr/include/features.h /usr/include/sys/cdefs.h
+dram.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
+dram.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h
+dram.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+dram.o: /usr/include/_G_config.h /usr/include/wchar.h
dram.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
dram.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
dram.o: /usr/include/endian.h /usr/include/bits/endian.h
@@ -154,7 +156,7 @@ dram.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
dram.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
dram.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
dram.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h delayqueue.h
-dram.o: /usr/include/assert.h ../cuda-sim/dram_callback.h
+dram.o: /usr/include/assert.h ../cuda-sim/dram_callback.h mem_latency_stat.h
dram_sched.o: dram_sched.h dram.h /usr/include/stdio.h
dram_sched.o: /usr/include/features.h /usr/include/sys/cdefs.h
dram_sched.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
@@ -171,14 +173,9 @@ dram_sched.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
dram_sched.o: /usr/include/alloca.h delayqueue.h /usr/include/assert.h
dram_sched.o: ../cuda-sim/dram_callback.h shader.h /usr/include/math.h
dram_sched.o: /usr/include/bits/huge_val.h /usr/include/bits/mathdef.h
-dram_sched.o: /usr/include/bits/mathcalls.h /usr/include/limits.h
-dram_sched.o: /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h
-dram_sched.o: /usr/include/linux/limits.h /usr/include/bits/posix2_lim.h
-dram_sched.o: ../cuda-sim/ptx.tab.h gpu-cache.h ../abstract_hardware_model.h
-dram_sched.o: stack.h gpu-sim.h /usr/include/zlib.h /usr/include/zconf.h
-dram_sched.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
-dram_sched.o: /usr/include/bits/confname.h /usr/include/getopt.h
-dram_sched.o: ../option_parser.h mem_fetch.h addrdec.h gpu-misc.h
+dram_sched.o: /usr/include/bits/mathcalls.h ../cuda-sim/ptx.tab.h gpu-cache.h
+dram_sched.o: ../abstract_hardware_model.h stack.h scoreboard.h gpu-sim.h
+dram_sched.o: gpu-misc.h mem_latency_stat.h
dwf.o: dwf.h ../abstract_hardware_model.h histogram.h /usr/include/string.h
dwf.o: /usr/include/features.h /usr/include/sys/cdefs.h
dwf.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
@@ -197,7 +194,10 @@ gpu-cache.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
gpu-cache.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
gpu-cache.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
gpu-cache.o: ../abstract_hardware_model.h gpu-misc.h addrdec.h
-gpu-cache.o: /usr/include/assert.h ../option_parser.h /usr/include/string.h
+gpu-cache.o: /usr/include/assert.h ../option_parser.h stat-tool.h
+gpu-cache.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h
+gpu-cache.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
+gpu-cache.o: /usr/include/getopt.h gpu-sim.h /usr/include/string.h
gpu-misc.o: gpu-misc.h
gpu-sim.o: gpu-sim.h /usr/include/stdio.h /usr/include/features.h
gpu-sim.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
@@ -216,15 +216,15 @@ gpu-sim.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
gpu-sim.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h
gpu-sim.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
gpu-sim.o: /usr/include/getopt.h ../option_parser.h shader.h
-gpu-sim.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
-gpu-sim.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
-gpu-sim.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h
-gpu-sim.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h
+gpu-sim.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h
+gpu-sim.o: ../cuda-sim/dram_callback.h gpu-cache.h
gpu-sim.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h
-gpu-sim.o: mem_fetch.h addrdec.h gpu-misc.h icnt_wrapper.h dwf.h
-gpu-sim.o: warp_tracker.h cflogger.h l2cache.h ../cuda-sim/ptx-stats.h
+gpu-sim.o: scoreboard.h mem_fetch.h addrdec.h gpu-misc.h icnt_wrapper.h dwf.h
+gpu-sim.o: warp_tracker.h stat-tool.h l2cache.h ../cuda-sim/ptx-stats.h
gpu-sim.o: ../intersim/statwraper.h ../debug.h ../abstract_hardware_model.h
-gpu-sim.o: /usr/include/string.h mem_latency_stat.h
+gpu-sim.o: ../gpgpusim_entrypoint.h ../cuda-sim/cuda-sim.h
+gpu-sim.o: ../cuda-sim/dram_callback.h mem_latency_stat.h
+gpu-sim.o: /usr/include/string.h
icnt_wrapper.o: icnt_wrapper.h /usr/include/assert.h /usr/include/features.h
icnt_wrapper.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
icnt_wrapper.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
@@ -239,7 +239,14 @@ icnt_wrapper.o: ../intersim/network.hpp ../intersim/credit.hpp
icnt_wrapper.o: ../intersim/router.hpp ../intersim/buffer_state.hpp
icnt_wrapper.o: ../intersim/stats.hpp ../intersim/traffic.hpp
icnt_wrapper.o: ../intersim/routefunc.hpp ../intersim/outputset.hpp
-icnt_wrapper.o: ../intersim/injection.hpp
+icnt_wrapper.o: ../intersim/injection.hpp ../option_parser.h
+icnt_wrapper.o: /usr/include/stdlib.h /usr/include/sys/types.h
+icnt_wrapper.o: /usr/include/time.h /usr/include/endian.h
+icnt_wrapper.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
+icnt_wrapper.o: /usr/include/sys/select.h /usr/include/bits/select.h
+icnt_wrapper.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+icnt_wrapper.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+icnt_wrapper.o: /usr/include/alloca.h
l2cache.o: /usr/include/stdlib.h /usr/include/features.h
l2cache.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
l2cache.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
@@ -256,12 +263,58 @@ l2cache.o: /usr/include/bits/sys_errlist.h /usr/include/string.h
l2cache.o: ../tr1_hash_map.h ../option_parser.h mem_fetch.h shader.h
l2cache.o: /usr/include/math.h /usr/include/bits/huge_val.h
l2cache.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
-l2cache.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
-l2cache.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
-l2cache.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h
-l2cache.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h
-l2cache.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h addrdec.h
-l2cache.o: histogram.h l2cache.h ../intersim/statwraper.h
+l2cache.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h
+l2cache.o: ../cuda-sim/dram_callback.h gpu-cache.h
+l2cache.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h
+l2cache.o: scoreboard.h addrdec.h histogram.h l2cache.h
+l2cache.o: ../intersim/statwraper.h gpu-sim.h
+mem_latency_stat.o: ../abstract_hardware_model.h mem_latency_stat.h gpu-sim.h
+mem_latency_stat.o: gpu-misc.h shader.h /usr/include/stdio.h
+mem_latency_stat.o: /usr/include/features.h /usr/include/sys/cdefs.h
+mem_latency_stat.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
+mem_latency_stat.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h
+mem_latency_stat.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+mem_latency_stat.o: /usr/include/_G_config.h /usr/include/wchar.h
+mem_latency_stat.o: /usr/include/bits/stdio_lim.h
+mem_latency_stat.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h
+mem_latency_stat.o: /usr/include/sys/types.h /usr/include/time.h
+mem_latency_stat.o: /usr/include/endian.h /usr/include/bits/endian.h
+mem_latency_stat.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
+mem_latency_stat.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+mem_latency_stat.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+mem_latency_stat.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
+mem_latency_stat.o: /usr/include/math.h /usr/include/bits/huge_val.h
+mem_latency_stat.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
+mem_latency_stat.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h
+mem_latency_stat.o: ../cuda-sim/dram_callback.h gpu-cache.h delayqueue.h
+mem_latency_stat.o: stack.h dram.h scoreboard.h mem_fetch.h addrdec.h
+mem_latency_stat.o: ../option_parser.h stat-tool.h /usr/include/zlib.h
+mem_latency_stat.o: /usr/include/zconf.h /usr/include/unistd.h
+mem_latency_stat.o: /usr/include/bits/posix_opt.h
+mem_latency_stat.o: /usr/include/bits/confname.h /usr/include/getopt.h
+mem_latency_stat.o: ../cuda-sim/ptx-stats.h visualizer.h
+mem_latency_stat.o: /usr/include/string.h
+scoreboard.o: scoreboard.h /usr/include/stdio.h /usr/include/features.h
+scoreboard.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
+scoreboard.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
+scoreboard.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+scoreboard.o: /usr/include/libio.h /usr/include/_G_config.h
+scoreboard.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
+scoreboard.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h
+scoreboard.o: /usr/include/sys/types.h /usr/include/time.h
+scoreboard.o: /usr/include/endian.h /usr/include/bits/endian.h
+scoreboard.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
+scoreboard.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+scoreboard.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+scoreboard.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
+scoreboard.o: /usr/include/assert.h shader.h /usr/include/math.h
+scoreboard.o: /usr/include/bits/huge_val.h /usr/include/bits/mathdef.h
+scoreboard.o: /usr/include/bits/mathcalls.h ../cuda-sim/ptx.tab.h
+scoreboard.o: ../cuda-sim/dram_callback.h gpu-cache.h
+scoreboard.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h
+scoreboard.o: ../cuda-sim/ptx_sim.h ../cuda-sim/dram_callback.h
+scoreboard.o: ../tr1_hash_map.h ../cuda-sim/opcodes.h ../cuda-sim/opcodes.def
+scoreboard.o: ../cuda-sim/memory.h /usr/include/string.h
shader.o: shader.h /usr/include/stdio.h /usr/include/features.h
shader.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
shader.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
@@ -276,18 +329,20 @@ shader.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
shader.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
shader.o: /usr/include/math.h /usr/include/bits/huge_val.h
shader.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
+shader.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h
+shader.o: ../cuda-sim/dram_callback.h gpu-cache.h
+shader.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h
+shader.o: scoreboard.h gpu-sim.h addrdec.h ../option_parser.h dwf.h
+shader.o: warp_tracker.h stat-tool.h /usr/include/zlib.h /usr/include/zconf.h
+shader.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+shader.o: /usr/include/bits/confname.h /usr/include/getopt.h gpu-misc.h
+shader.o: ../cuda-sim/ptx_sim.h ../cuda-sim/dram_callback.h ../tr1_hash_map.h
+shader.o: ../cuda-sim/opcodes.h ../cuda-sim/opcodes.def ../cuda-sim/memory.h
+shader.o: /usr/include/string.h ../cuda-sim/ptx-stats.h
+shader.o: ../cuda-sim/cuda-sim.h mem_fetch.h mem_latency_stat.h visualizer.h
shader.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
shader.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
-shader.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h
-shader.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h
-shader.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h gpu-sim.h
-shader.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h
-shader.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
-shader.o: /usr/include/getopt.h ../option_parser.h mem_fetch.h addrdec.h
-shader.o: dwf.h warp_tracker.h cflogger.h gpu-misc.h ../cuda-sim/ptx_sim.h
-shader.o: ../cuda-sim/dram_callback.h ../cuda-sim/opcodes.h
-shader.o: ../cuda-sim/opcodes.def ../cuda-sim/ptx-stats.h
-shader.o: /usr/include/string.h
+shader.o: /usr/include/bits/posix2_lim.h
stack.o: stack.h ../abstract_hardware_model.h /usr/include/stdlib.h
stack.o: /usr/include/features.h /usr/include/sys/cdefs.h
stack.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
@@ -299,48 +354,46 @@ stack.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
stack.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
stack.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
stack.o: /usr/include/assert.h
-stat-tool.o: /usr/include/stdio.h /usr/include/features.h
-stat-tool.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-stat-tool.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-stat-tool.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-stat-tool.o: /usr/include/libio.h /usr/include/_G_config.h
-stat-tool.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
-stat-tool.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h
+stat-tool.o: stat-tool.h ../abstract_hardware_model.h /usr/include/stdio.h
+stat-tool.o: /usr/include/features.h /usr/include/sys/cdefs.h
+stat-tool.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
+stat-tool.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h
+stat-tool.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+stat-tool.o: /usr/include/_G_config.h /usr/include/wchar.h
+stat-tool.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+stat-tool.o: /usr/include/zlib.h /usr/include/zconf.h
stat-tool.o: /usr/include/sys/types.h /usr/include/time.h
stat-tool.o: /usr/include/endian.h /usr/include/bits/endian.h
stat-tool.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
stat-tool.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
stat-tool.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-stat-tool.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
-stat-tool.o: /usr/include/assert.h /usr/include/zlib.h /usr/include/zconf.h
-stat-tool.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
-stat-tool.o: /usr/include/bits/confname.h /usr/include/getopt.h histogram.h
-stat-tool.o: ../abstract_hardware_model.h cflogger.h
-visualizer.o: gpu-sim.h /usr/include/stdio.h /usr/include/features.h
+stat-tool.o: /usr/include/bits/pthreadtypes.h /usr/include/unistd.h
+stat-tool.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
+stat-tool.o: /usr/include/getopt.h /usr/include/stdlib.h
+stat-tool.o: /usr/include/alloca.h /usr/include/assert.h histogram.h
+visualizer.o: visualizer.h /usr/include/stdio.h /usr/include/features.h
visualizer.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
visualizer.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
visualizer.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
visualizer.o: /usr/include/libio.h /usr/include/_G_config.h
visualizer.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
-visualizer.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h
-visualizer.o: /usr/include/sys/types.h /usr/include/time.h
-visualizer.o: /usr/include/endian.h /usr/include/bits/endian.h
-visualizer.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
-visualizer.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
-visualizer.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-visualizer.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
-visualizer.o: /usr/include/math.h /usr/include/bits/huge_val.h
+visualizer.o: /usr/include/bits/sys_errlist.h /usr/include/zlib.h
+visualizer.o: /usr/include/zconf.h /usr/include/sys/types.h
+visualizer.o: /usr/include/time.h /usr/include/endian.h
+visualizer.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
+visualizer.o: /usr/include/sys/select.h /usr/include/bits/select.h
+visualizer.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+visualizer.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+visualizer.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+visualizer.o: /usr/include/bits/confname.h /usr/include/getopt.h gpu-sim.h
+visualizer.o: l2cache.h dram.h /usr/include/stdlib.h /usr/include/alloca.h
+visualizer.o: delayqueue.h /usr/include/assert.h ../cuda-sim/dram_callback.h
+visualizer.o: shader.h /usr/include/math.h /usr/include/bits/huge_val.h
visualizer.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
-visualizer.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h
-visualizer.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
-visualizer.o: /usr/include/getopt.h ../option_parser.h shader.h
-visualizer.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
-visualizer.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
-visualizer.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h
-visualizer.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h
-visualizer.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h
-visualizer.o: mem_fetch.h addrdec.h /usr/include/string.h
-visualizer.o: ../gpgpu-sim/shader.h ../gpgpu-sim/mem_fetch.h
+visualizer.o: ../cuda-sim/ptx.tab.h gpu-cache.h ../abstract_hardware_model.h
+visualizer.o: stack.h scoreboard.h ../option_parser.h mem_latency_stat.h
+visualizer.o: stat-tool.h /usr/include/string.h ../gpgpu-sim/shader.h
+visualizer.o: ../gpgpu-sim/mem_fetch.h addrdec.h
warp_tracker.o: warp_tracker.h ../abstract_hardware_model.h shader.h
warp_tracker.o: /usr/include/stdio.h /usr/include/features.h
warp_tracker.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
@@ -357,8 +410,6 @@ warp_tracker.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
warp_tracker.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
warp_tracker.o: /usr/include/math.h /usr/include/bits/huge_val.h
warp_tracker.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
-warp_tracker.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
-warp_tracker.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
-warp_tracker.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h
-warp_tracker.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h
-warp_tracker.o: delayqueue.h stack.h dram.h
+warp_tracker.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h
+warp_tracker.o: ../cuda-sim/dram_callback.h gpu-cache.h delayqueue.h stack.h
+warp_tracker.o: dram.h scoreboard.h gpu-sim.h
diff --git a/src/gpgpu-sim/delayqueue.cc b/src/gpgpu-sim/delayqueue.cc
deleted file mode 100644
index 659018b..0000000
--- a/src/gpgpu-sim/delayqueue.cc
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * delayqueue.c
- *
- * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda,
- * Ivan Sham, Henry Tran 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 "delayqueue.h"
-#include "gpu-misc.h"
-#include "gpu-sim.h"
-#include "../intersim/statwraper.h"
-
-unsigned char dq_full( delay_queue* dq )
-{
- if (dq->max_len && dq->length >= dq->max_len)
- return 1;
- return 0;
-}
-
-unsigned char dq_empty(delay_queue* dq )
-{
- return(dq->head == NULL)?1:0;
-}
-
-unsigned int dq_n_element(delay_queue* dq )
-{
- return(dq->n_element);
-}
-
-unsigned char dq_push(delay_queue* dq, void* data) {
- if (dq->max_len) assert(dq->length < dq->max_len);
- if (dq->head) {
- if (dq->tail->data || dq->length < dq->min_len) {
- dq->tail->next = (delay_data*) malloc(sizeof(delay_data));
- dq->tail = dq->tail->next;
- dq->length++;
- dq->n_element++;
- }
- } else {
- dq->head = dq->tail = (delay_data*) malloc(sizeof(delay_data));
- dq->length++;
- dq->n_element++;
- }
- dq->tail->next = NULL;
- dq->tail->time_elapsed = dq->latency;
- dq->tail->data = (void*)data;
- dq->tail->push_time = gpu_sim_cycle;
- return 1;
-}
-
-void* dq_top(delay_queue* dq) {
- if (dq->head) {
- return dq->head->data;
- } else {
- return NULL;
- }
-}
-
-void* dq_pop(delay_queue* dq) {
- delay_data* next;
- void* data;
- if (dq->head) {
- if (dq->head->time_elapsed) {
- dq->head->time_elapsed--;
- data = NULL;
- } else {
- next = dq->head->next;
- data = dq->head->data;
- StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - dq->head->push_time));
- if ( dq->head == dq->tail ) {
- assert( next == NULL );
- dq->tail = NULL;
- }
- free(dq->head);
- dq->head = next;
- dq->length--;
- if (dq->length == 0) {
- assert( dq->head == NULL );
- dq->tail = dq->head;
- }
- dq->n_element--;
- }
- if (dq->min_len && dq->length < dq->min_len) {
- dq_push(dq,NULL);
- dq->n_element--; // uncount NULL elements inserted to create delays
- }
- } else {
- data = NULL;
- }
- return data;
-}
-
-void dq_set_min_length(delay_queue* dq, unsigned int new_min_len) {
- if (new_min_len == dq->min_len) return;
-
- if (new_min_len > dq->min_len) {
- dq->min_len = new_min_len;
- while (dq->length < dq->min_len) {
- dq_push(dq,NULL);
- dq->n_element--; // uncount NULL elements inserted to create delays
- }
- } else {
- // in this branch imply that the original min_len is larger then 0
- // ie. dq->head != 0
- assert(dq->head);
- dq->min_len = new_min_len;
- while ((dq->length > dq->min_len) && (dq->tail->data == 0)) {
- delay_data *iter;
- iter = dq->head;
- while (iter && (iter->next != dq->tail))
- iter = iter->next;
- if (!iter) {
- // there is only one node, and that node is empty
- assert(dq->head->data == 0);
- dq_pop(dq);
- } else {
- // there are more than one node, and tail node is empty
- assert(iter->next == dq->tail);
- free(dq->tail);
- dq->tail = iter;
- dq->tail->next = 0;
- dq->length--;
- }
- }
- }
-}
-
-void dq_remove(void* data, delay_queue* dq)
-{
- // removes an item from the queue without deallocating the memory
- delay_data* ptr = NULL;
- delay_data* temp = NULL;
-
- assert(dq);
- assert(data);
-
- ptr = dq->head;
- if (ptr) {
- if (ptr->data == data) {
- StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - ptr->push_time));
- dq->head = ptr->next;
- if ( dq->head == NULL )
- dq->tail = NULL;
- dq->length--;
- return;
- }
- while (ptr->next) {
- if (ptr->next->data == data) {
- temp = ptr->next;
- StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - temp->push_time));
- if ( ptr->next == dq->tail ) {
- dq->tail = ptr;
- }
- ptr->next = ptr->next->next;
- dq->length--;
- return;
- }
- ptr = ptr->next;
- }
- }
-}
-
-void removeEntry(void* data, delay_queue** dqq, int size_dq)
-{
- int i;
- delay_data* ptr = NULL;
- delay_queue* dq = NULL;
- delay_data* temp = NULL;
-
- assert(dqq);
- assert(data);
-
-
- for (i = 0; i<size_dq; i++) {
- dq = dqq[i];
- ptr = dq->head;
- if (ptr) {
- if (ptr->data == data) {
- dq->head = ptr->next;
- if ( dq->head == NULL )
- dq->tail = NULL;
- StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - ptr->push_time));
- free(ptr);
- dq->length--;
- return;
- }
- while (ptr->next) {
- if (ptr->next->data == data) {
- temp = ptr->next;
- if ( ptr->next == dq->tail ) {
- dq->tail = ptr;
- }
- ptr->next = ptr->next->next;
- StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - temp->push_time));
- free(temp);
- dq->length--;
- return;
- }
- ptr = ptr->next;
- }
- }
-
- }
-}
-
-static int dq_uid_counter = 0;
-
-delay_queue* dq_create(const char* name, unsigned int latency, unsigned int min_len, unsigned int max_len) {
- unsigned i;
- delay_queue* dq;
- dq = (delay_queue*) malloc(sizeof(delay_queue));
- dq->name = name;
- dq->latency = latency;
- dq->min_len = min_len;
- dq->max_len = max_len;
- dq->length = 0;
- dq->n_element = 0;
- dq->head = NULL;
- dq->tail = NULL;
- for (i=0;i<min_len;i++) dq_push(dq,NULL);
- dq->uid = dq_uid_counter;
- dq_uid_counter++;
- if (1) {
- dq->lat_stat = StatCreate(dq->name,1,32);
- }
- dq->max_size_stat = 0;
- dq->avg_size_stat =0.0 ;
- return dq;
-}
-
-void dq_print(delay_queue* dq) {
- delay_data* ddp = dq->head;
- printf("%s(%d): ", dq->name, dq->length);
- while (ddp) {
- printf("%p ", ddp->data);
- ddp = ddp->next;
- }
- printf("\n");
-}
-
-void dq_free(delay_queue* dq) {
- while (dq->head) {
- dq->tail = dq->head;
- dq->head = dq->head->next;
- free(dq->tail);
- }
- free(dq);
- dq = NULL;
-}
-
-void dq_update_stat(delay_queue* dq) {
- if (dq->n_element > dq->max_size_stat) {
- dq->max_size_stat = dq->n_element;
- }
- dq->avg_size_stat = (dq->avg_size_stat*dq->n_stat_samples + dq->n_element)/(++dq->n_stat_samples);
-}
-void dq_print_stat(delay_queue* dq) {
- printf("Max Length: %d, Average Length: %f\n",dq->max_size_stat,dq->avg_size_stat );
-}
-
-
-#ifdef TEST_DQ
-
-void regresstion_test01() {
- delay_queue *dqa, *dqb;
- int i;
- int a[7];
- for (i=0;i<7;i++) a[i]=i;
-
- dqa = dq_create("dqa", 0, 7, 0);
- for (i=0;i<3;i++) dq_push(dqa, &a[i]);
-
- for (i=0;i<6;i++) {
- dq_print(dqa);
- assert(dq_pop(dqa) == 0);
- }
- dq_print(dqa);
- assert(dq_pop(dqa) == &a[0]);
-
- // shortening queue
- dq_print(dqa);
- dq_set_min_length(dqa, 4);
- // see if data in the queue still persist
- dq_print(dqa);
- assert(dq_pop(dqa) == &a[1]);
- // see if the queue behave with min length = 4
- dq_push(dqa, &a[3]);
- dq_print(dqa);
- assert(dq_pop(dqa) == &a[2]);
- for (i=0;i<2;i++) {
- dq_print(dqa);
- assert(dq_pop(dqa) == 0);
- }
- dq_print(dqa);
- assert(dq_pop(dqa) == &a[3]);
-
- // lengthening queue
- dq_set_min_length(dqa, 6);
- dq_push(dqa, &a[4]);
- dq_push(dqa, &a[5]);
- for (i=0;i<5;i++) {
- dq_print(dqa);
- assert(dq_pop(dqa) == 0);
- }
- dq_print(dqa);
- assert(dq_pop(dqa) == &a[4]);
-
- // queue with no min length
- dq_set_min_length(dqa, 0);
- dq_print(dqa);
- assert(dq_pop(dqa) == &a[5]);
- dq_print(dqa);
- dq_push(dqa, &a[6]);
- dq_print(dqa);
- assert(dq_pop(dqa) == &a[6]);
-
- // lengthening the queue, then shorten it again,
- // but with some data exceeding the new min length
- // the data should retain.
- dq_print(dqa);
- dq_set_min_length(dqa, 7);
- dq_print(dqa);
- dq_push(dqa, &a[0]);
- assert(dq_pop(dqa) == 0);
- dq_print(dqa);
- dq_set_min_length(dqa, 4);
- dq_print(dqa);
- assert(dq_pop(dqa) == 0);
- assert(dq_pop(dqa) == 0);
- assert(dq_pop(dqa) == 0);
- assert(dq_pop(dqa) == 0);
- assert(dq_pop(dqa) == 0);
- // This is the 7th pop: min-length is obeyed
- assert(dq_pop(dqa) == &a[0]);
- dq_print(dqa);
-
- // Shortening a queue with null entry only
- dq_set_min_length(dqa, 0);
- assert(dqa->length == 0);
- dq_print(dqa);
-
- // Lengthening
- dq_set_min_length(dqa, 6);
- assert(dqa->length == 6);
- dq_print(dqa);
-
- // Shortening a queue with null entry only
- dq_set_min_length(dqa, 3);
- assert(dqa->length == 3);
- dq_print(dqa);
-
- dq_free(dqa);
- printf("regression test 01 passed!\n");
-}
-
-int regresstion_test00() {
- delay_queue *dqa, *dqb, *dqc, *dqd;
- int i;
- int a[4];
- int *b;
- for (i=0;i<4;i++) a[i]=i;
- dqa = dq_create("dqa", 0, 4, 0);
- dqb = dq_create("dqb", 0, 10, 0);
- dq_print(dqa);
- dq_print(dqb);
- dq_push(dqa,a);
- dq_print(dqa);
- dq_pop(dqa);
- dq_print(dqa);
- dq_push(dqa,a);
- dq_print(dqa);
- dq_pop(dqa);
- dq_print(dqa);
- dq_pop(dqa);
- dq_print(dqa);
- b = dq_pop(dqa);
- dq_print(dqa);
- for (i=0;i<4;i++) printf("%d\n",b[i]);
- dqc = dq_create("dqc", 0, 0, 3);
- for (i=0;i<4;i++) {
- if (!dq_push(dqc,&a[i])) printf("cannot push.\n");
- dq_print(dqc);
- }
- dqd = dq_create("dqd", 0, 2, 3);
- if (!dq_push(dqd,&a[0])) printf("cannot push.\n");
- dq_print(dqd);
- if (!dq_push(dqd,&a[1])) printf("cannot push.\n");
- dq_print(dqd);
- if (!dq_push(dqd,&a[2])) printf("cannot push.\n");
- dq_print(dqd);
- dq_pop(dqd);
- if (!dq_push(dqd,&a[3])) printf("cannot push.\n");
- dq_print(dqd);
-
- dq_free(dqa);
- dq_free(dqb);
- dq_free(dqc);
- dq_free(dqd);
-
- return 0;
-}
-
-int main() {
- regresstion_test01();
- return 0;
-}
-
-
-#endif
diff --git a/src/gpgpu-sim/delayqueue.h b/src/gpgpu-sim/delayqueue.h
index a8d6fc1..8392460 100644
--- a/src/gpgpu-sim/delayqueue.h
+++ b/src/gpgpu-sim/delayqueue.h
@@ -70,51 +70,167 @@
#ifndef DELAYQUEUE_H
#define DELAYQUEUE_H
-typedef struct delay_data_t delay_data;
-struct delay_data_t {
- void *data;
- unsigned int time_elapsed;
- delay_data *next;
+#include "../intersim/statwraper.h"
+#include "gpu-misc.h"
+
+template <class T>
+struct fifo_data {
+ T *m_data;
+ fifo_data *m_next;
unsigned long long push_time; //for stat collection
};
-typedef struct {
- const char* name;
- int uid;
+template <class T>
+class fifo_pipeline {
+public:
+ fifo_pipeline(const char* nm, unsigned int minlen, unsigned int maxlen, unsigned long long current_time )
+ {
+ m_name = nm;
+ m_min_len = minlen;
+ m_max_len = maxlen;
+ m_length = 0;
+ m_n_element = 0;
+ m_head = NULL;
+ m_tail = NULL;
+ for (unsigned i=0;i<m_min_len;i++)
+ push(NULL,current_time);
+ m_lat_stat = StatCreate(m_name,1,32);
+ }
+
+ ~fifo_pipeline()
+ {
+ while (m_head) {
+ m_tail = m_head;
+ m_head = m_head->m_next;
+ delete m_tail;
+ }
+ }
+
+ void push(T* data, unsigned long long current_time )
+ {
+ if (m_max_len) assert(m_length < m_max_len);
+ if (m_head) {
+ if (m_tail->m_data || m_length < m_min_len) {
+ m_tail->m_next = new fifo_data<T>();
+ m_tail = m_tail->m_next;
+ m_length++;
+ m_n_element++;
+ }
+ } else {
+ m_head = m_tail = new fifo_data<T>();
+ m_length++;
+ m_n_element++;
+ }
+ m_tail->m_next = NULL;
+ m_tail->m_data = data;
+ m_tail->push_time = current_time;
+ }
+
+ T* pop( unsigned long long current_time )
+ {
+ fifo_data<T>* next;
+ T* data;
+ if (m_head) {
+ next = m_head->m_next;
+ data = m_head->m_data;
+ StatAddSample(m_lat_stat, LOGB2 (current_time - m_head->push_time));
+ if ( m_head == m_tail ) {
+ assert( next == NULL );
+ m_tail = NULL;
+ }
+ delete m_head;
+ m_head = next;
+ m_length--;
+ if (m_length == 0) {
+ assert( m_head == NULL );
+ m_tail = m_head;
+ }
+ m_n_element--;
+ if (m_min_len && m_length < m_min_len) {
+ push(NULL,current_time);
+ m_n_element--; // uncount NULL elements inserted to create delays
+ }
+ } else {
+ data = NULL;
+ }
+ return data;
+ }
- unsigned int latency;
- unsigned int min_len;
- unsigned int max_len;
- unsigned int length;
- unsigned int n_element;
+ T* top()
+ {
+ if (m_head) {
+ return m_head->m_data;
+ } else {
+ return NULL;
+ }
+ }
- delay_data *head;
- delay_data *tail;
+ void set_min_length(unsigned int new_min_len, unsigned long long current_time)
+ {
+ if (new_min_len == m_min_len) return;
+
+ if (new_min_len > m_min_len) {
+ m_min_len = new_min_len;
+ while (m_length < m_min_len) {
+ push(NULL,current_time);
+ m_n_element--; // uncount NULL elements inserted to create delays
+ }
+ } else {
+ // in this branch imply that the original min_len is larger then 0
+ // ie. head != 0
+ assert(m_head);
+ m_min_len = new_min_len;
+ while ((m_length > m_min_len) && (m_tail->m_data == 0)) {
+ fifo_data<T> *iter;
+ iter = m_head;
+ while (iter && (iter->m_next != m_tail))
+ iter = iter->m_next;
+ if (!iter) {
+ // there is only one node, and that node is empty
+ assert(m_head->m_data == 0);
+ pop(current_time);
+ } else {
+ // there are more than one node, and tail node is empty
+ assert(iter->m_next == m_tail);
+ delete m_tail;
+ m_tail = iter;
+ m_tail->m_next = 0;
+ m_length--;
+ }
+ }
+ }
+ }
- void* lat_stat; //a pointer to latency stats distribution structure
- //occupancy stat
- unsigned int max_size_stat;
- unsigned int n_stat_samples;
- float avg_size_stat;
-} delay_queue;
+ bool full() const { return (m_max_len && m_length >= m_max_len); }
+ bool empty() const { return m_head == NULL; }
+ unsigned get_n_element() const { return m_n_element; }
+ unsigned get_length() const { return m_length; }
+ unsigned get_max_len() const { return m_max_len; }
+ void* get_lat_stat() { return m_lat_stat; }
-unsigned char dq_full(delay_queue* dq );
-unsigned char dq_empty(delay_queue* dq );
-unsigned int dq_n_element(delay_queue* dq );
-unsigned char dq_push(delay_queue* dq, void* data);
-void* dq_pop(delay_queue* dq);
-void dq_set_min_length(delay_queue* dq, unsigned int new_min_len);
-void removeEntry(void* data, delay_queue** dq, int size_dq);
-delay_queue* dq_create( const char* name,
- unsigned int latency,
- unsigned int min_len,
- unsigned int max_len);
-void dq_remove(void* data, delay_queue* dq);
-void dq_print(delay_queue* dq);
-void dq_free(delay_queue* dq);
-void* dq_top(delay_queue* dq);//return the data in the head without poping the queue
+ void print() const
+ {
+ fifo_data<T>* ddp = m_head;
+ printf("%s(%d): ", m_name, m_length);
+ while (ddp) {
+ printf("%p ", ddp->m_data);
+ ddp = ddp->m_next;
+ }
+ printf("\n");
+ }
-void dq_update_stat(delay_queue* dq);
-void dq_print_stat(delay_queue* dq);
+private:
+ const char* m_name;
+
+ unsigned int m_min_len;
+ unsigned int m_max_len;
+ unsigned int m_length;
+ unsigned int m_n_element;
+
+ fifo_data<T> *m_head;
+ fifo_data<T> *m_tail;
+
+ void* m_lat_stat; //a pointer to latency stats distribution structure
+};
#endif
diff --git a/src/gpgpu-sim/dram.cc b/src/gpgpu-sim/dram.cc
index 9f76b96..3182b38 100644
--- a/src/gpgpu-sim/dram.cc
+++ b/src/gpgpu-sim/dram.cc
@@ -68,195 +68,163 @@
#include "gpu-misc.h"
#include "dram.h"
#include "mem_latency_stat.h"
+#include "dram_sched.h"
#ifdef DRAM_VERIFY
int PRINT_CYCLE = 0;
#endif
-dram_t* dram_create( unsigned int id, unsigned int nbk,
- unsigned int tCCD, unsigned int tRRD,
- unsigned int tRCD, unsigned int tRAS,
- unsigned int tRP, unsigned int tRC,
- unsigned int CL, unsigned int WL,
- unsigned int BL, unsigned int tWTR,
- unsigned int busW, unsigned int queue_limit,
- unsigned char scheduler_type )
+template class fifo_pipeline<mem_fetch>;
+template class fifo_pipeline<dram_req_t>;
+
+dram_t::dram_t( unsigned int partition_id, struct memory_config *config )
{
- dram_t *dm;
- unsigned i;
+ id = partition_id;
+ m_stats = NULL;
+ m_config = config;
- dm = (dram_t*)calloc(1,sizeof(dram_t));
- dm = new (dm) dram_t();
+ BL=m_config->gpgpu_dram_burst_length;
+ busW=m_config->gpgpu_dram_buswidth;
- dm->id = id;
+ sscanf(m_config->gpgpu_dram_timing_opt,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",&nbk,&tCCD,&tRRD,&tRCD,&tRAS,&tRP,&tRC,&CL,&WL,&tWTR);
+ m_config->gpu_mem_n_bk = nbk;
- dm->nbk = nbk;
- dm->tCCD = tCCD;
- dm->tRRD = tRRD;
- dm->tRCD = tRCD;
- dm->tRCDWR = tRCD - (WL + 1); //formula given in datasheet
- dm->tRAS = tRAS;
- dm->tRP = tRP;
- dm->tRC = tRC;
- dm->CL = CL;
- dm->WL = WL;
- dm->BL = BL;
+ tRCDWR = tRCD - (WL + 1); //formula given in datasheet
+ tRTW = (CL+(BL/2)+2-WL); //read to write time according to datasheet
- dm->tRTW = (CL+(BL/2)+2-WL); //read to write time according to datasheet
- dm->tWTR = tWTR;
+ CCDc = 0;
+ RRDc = 0;
+ RTWc = 0;
+ WTRc = 0;
- dm->busW = busW;
+ rw = READ; //read mode is default
- dm->CCDc = 0;
- dm->RRDc = 0;
- dm->RTWc = 0;
- dm->WTRc = 0;
+ bk = (bank_t**) calloc(sizeof(bank_t*),nbk);
+ bk[0] = (bank_t*) calloc(sizeof(bank_t),nbk);
+ for (unsigned i=1;i<nbk;i++)
+ bk[i] = bk[0] + i;
+ for (unsigned i=0;i<nbk;i++)
+ bk[i]->state = BANK_IDLE;
- dm->rw = READ; //read mode is default
+ prio = 0;
+ rwq = new fifo_pipeline<dram_req_t>("rwq",CL,CL+1,gpu_sim_cycle);
+ mrqq = new fifo_pipeline<dram_req_t>("mrqq",0,0,gpu_sim_cycle);
+ returnq = new fifo_pipeline<mem_fetch>("dramreturnq",0,m_config->gpgpu_dram_sched_queue_size,gpu_sim_cycle);
+ m_fast_ideal_scheduler = NULL;
+ if ( m_config->scheduler_type == DRAM_IDEAL_FAST )
+ m_fast_ideal_scheduler = new ideal_dram_scheduler(this);
+ n_cmd = 0;
+ n_activity = 0;
+ n_nop = 0;
+ n_act = 0;
+ n_pre = 0;
+ n_rd = 0;
+ n_wr = 0;
+ n_req = 0;
+ max_mrqs_temp = 0;
+ bwutil = 0;
+ max_mrqs = 0;
- dm->bk = (bank_t**) calloc(sizeof(bank_t*),dm->nbk);
- dm->bk[0] = (bank_t*) calloc(sizeof(bank_t),dm->nbk);
- for (i=1;i<dm->nbk;i++) {
- dm->bk[i] = dm->bk[0] + i;
+ for (unsigned i=0;i<10;i++) {
+ dram_util_bins[i]=0;
+ dram_eff_bins[i]=0;
}
- for (i=0;i<dm->nbk;i++) {
- dm->bk[i]->state = BANK_IDLE;
- }
- dm->prio = 0;
- dm->rwq = dq_create("rwq",0,dm->CL,dm->CL+1);
- dm->mrqq = dq_create("mrqq",0,0,0);
- dm->queue_limit = queue_limit;
-
- dm->returnq = dq_create("dramreturnq",0,0, queue_limit);
-
- dm->m_fast_ideal_scheduler = NULL;
- if ( scheduler_type == DRAM_IDEAL_FAST )
- dm->m_fast_ideal_scheduler = alloc_fast_ideal_scheduler(dm);
-
-
- dm->n_cmd = 0;
- dm->n_activity = 0;
- dm->n_nop = 0;
- dm->n_act = 0;
- dm->n_pre = 0;
- dm->n_rd = 0;
- dm->n_wr = 0;
- dm->n_req = 0;
- dm->max_mrqs_temp = 0;
+ last_n_cmd = last_n_activity = last_bwutil = 0;
- dm->bwutil = 0;
+ n_cmd_partial = 0;
+ n_activity_partial = 0;
+ n_nop_partial = 0;
+ n_act_partial = 0;
+ n_pre_partial = 0;
+ n_req_partial = 0;
+ ave_mrqs_partial = 0;
+ bwutil_partial = 0;
- dm->max_mrqs = 0;
-
- dm->scheduler_type = scheduler_type;
-
- dm->realistic_scheduler_mode = READ; //realistic scheduler defaults to read
- for (i=0;i<10;i++) {
- dm->dram_util_bins[i]=0;
- dm->dram_eff_bins[i]=0;
- }
- dm->last_n_cmd = dm->last_n_activity = dm->last_bwutil = 0;
-
- dm->n_cmd_partial = 0;
- dm->n_activity_partial = 0;
- dm->n_nop_partial = 0;
- dm->n_act_partial = 0;
- dm->n_pre_partial = 0;
- dm->n_req_partial = 0;
- dm->ave_mrqs_partial = 0;
- dm->bwutil_partial = 0;
- return dm;
+ if ( queue_limit() )
+ mrqq_Dist = StatCreate("mrqq_length",1, queue_limit());
+ else //queue length is unlimited;
+ mrqq_Dist = StatCreate("mrqq_length",1,64); //track up to 64 entries
}
-void dram_free( dram_t *dm )
-{
- dq_free(dm->mrqq);
- dq_free(dm->rwq);
- dq_free( dm->returnq );
-
- free(dm->bk[0]);
- free(dm->bk);
- free(dm);
-}
-
-int dram_full( dram_t *dm )
+int dram_t::full()
{
int full = 0;
- if ( dm->queue_limit == 0 ) return 0;
- if ( dm->scheduler_type == DRAM_IDEAL_FAST ) {
- unsigned nreqs = fast_scheduler_queue_length(dm) + dq_n_element(dm->mrqq);
- full = (nreqs >= dm->queue_limit);
+ if ( m_config->gpgpu_dram_sched_queue_size == 0 ) return 0;
+ if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) {
+ unsigned nreqs = m_fast_ideal_scheduler->num_pending() + mrqq->get_n_element();
+ full = (nreqs >= m_config->gpgpu_dram_sched_queue_size);
} else {
- full = (dm->mrqq->length >= dm->queue_limit);
+ full = (mrqq->get_length() >= m_config->gpgpu_dram_sched_queue_size);
}
return full;
}
-unsigned int dram_que_length( dram_t *dm )
+unsigned int dram_t::que_length() const
{
unsigned nreqs = 0;
- if (dm->scheduler_type == DRAM_IDEAL_FAST ) {
- nreqs = fast_scheduler_queue_length(dm);
+ if (m_config->scheduler_type == DRAM_IDEAL_FAST ) {
+ nreqs = m_fast_ideal_scheduler->num_pending();
} else {
- nreqs = dm->mrqq->length ;
+ nreqs = mrqq->get_length();
}
return nreqs;
}
-void dram_push( dram_t *dm, unsigned int bank,
- unsigned int row, unsigned int col,
- unsigned int nbytes, unsigned int write,
- unsigned int wid,
- unsigned int sid, int cache_hits_waiting, unsigned long long addr,
- void *data )
+bool dram_t::returnq_full() const
{
- dram_req_t *mrq;
-
- if (bank>=dm->nbk) printf("ERROR: no such bank exist in DRAM %d\n", bank);
+ return returnq->full();
+}
- mrq = (dram_req_t *) malloc(sizeof(dram_req_t));
+unsigned int dram_t::queue_limit() const
+{
+ return m_config->gpgpu_dram_sched_queue_size;
+}
- mrq->bk = bank;
- mrq->row = row;
- mrq->col = col;
- mrq->nbytes = nbytes;
- mrq->txbytes = 0;
- mrq->dqbytes = 0;
- mrq->data = data;
- mrq->timestamp = gpu_tot_sim_cycle + gpu_sim_cycle;
- mrq->cache_hits_waiting = cache_hits_waiting;
- mrq->addr = addr;
- mrq->insertion_time = (unsigned) gpu_sim_cycle;
- if (!write) {
- mrq->rw = READ; //request is a read
- } else {
- mrq->rw = WRITE; //request is a write
- }
+dram_req_t::dram_req_t( class mem_fetch *mf )
+{
+ bk = mf->tlx.bk;
+ row = mf->tlx.row;
+ col = mf->tlx.col;
+ nbytes = mf->nbytes_L1;
+ txbytes = 0;
+ dqbytes = 0;
+ data = mf;
+ timestamp = gpu_tot_sim_cycle + gpu_sim_cycle;
+ cache_hits_waiting = mf->cache_hits_waiting;
+ addr = mf->addr;
+ insertion_time = (unsigned) gpu_sim_cycle;
+ rw = data->m_write?WRITE:READ;
+}
- dq_push(dm->mrqq,mrq);
- dm->n_req += 1;
- dm->n_req_partial += 1;
+void dram_t::push( class mem_fetch *data )
+{
+ assert(data->tlx.bk<nbk);
+ dram_req_t *mrq = new dram_req_t(data);
+ mrqq->push(mrq,gpu_sim_cycle);
- if ( dm->scheduler_type == DRAM_IDEAL_FAST ) {
- unsigned nreqs = fast_scheduler_queue_length(dm);
- if ( nreqs > dm->max_mrqs_temp)
- dm->max_mrqs_temp = nreqs;
+ // stats...
+ n_req += 1;
+ n_req_partial += 1;
+ if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) {
+ unsigned nreqs = m_fast_ideal_scheduler->num_pending();
+ if ( nreqs > max_mrqs_temp)
+ max_mrqs_temp = nreqs;
} else {
- dm->max_mrqs_temp = (dm->max_mrqs_temp > dm->mrqq->length)? dm->max_mrqs_temp : dm->mrqq->length;
+ max_mrqs_temp = (max_mrqs_temp > mrqq->get_length())? max_mrqs_temp : mrqq->get_length();
}
+ m_stats->memlatstat_dram_access(data);
}
-void scheduler_fifo(dram_t* dm)
+void dram_t::scheduler_fifo()
{
- if (dm->mrqq->head) {
- dram_req_t *head_mrqq;
+ if (!mrqq->empty()) {
unsigned int bkn;
- head_mrqq = (dram_req_t *)dm->mrqq->head->data;
+ dram_req_t *head_mrqq = mrqq->top();
bkn = head_mrqq->bk;
- if (!dm->bk[bkn]->mrq) {
- dm->bk[bkn]->mrq = (dram_req_t*) dq_pop(dm->mrqq);
+ if (!bk[bkn]->mrq) {
+ bk[bkn]->mrq = mrqq->pop(gpu_sim_cycle);
}
}
}
@@ -265,7 +233,7 @@ void scheduler_fifo(dram_t* dm)
#define DEC2ZERO(x) x = (x)? (x-1) : 0;
#define SWAP(a,b) a ^= b; b ^= a; a ^= b;
-void dram_issueCMD (dram_t* dm)
+void dram_t::issueCMD()
{
unsigned i,j,k;
unsigned char issued;
@@ -274,206 +242,196 @@ void dram_issueCMD (dram_t* dm)
/* check if the upcoming request is on an idle bank */
/* Should we modify this so that multiple requests are checked? */
- switch (dm->scheduler_type) {
- case DRAM_FIFO:
- scheduler_fifo(dm);
- break;
- case DRAM_IDEAL_FAST:
- fast_scheduler_ideal(dm);
- break;
+ switch (m_config->scheduler_type) {
+ case DRAM_FIFO: scheduler_fifo(); break;
+ case DRAM_IDEAL_FAST: fast_scheduler_ideal(); break;
default:
printf("Error: Unknown DRAM scheduler type\n");
assert(0);
}
- if ( dm->scheduler_type == DRAM_IDEAL_FAST ) {
- unsigned nreqs = fast_scheduler_queue_length(dm);
- if ( nreqs > dm->max_mrqs) {
- dm->max_mrqs = nreqs;
+ if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) {
+ unsigned nreqs = m_fast_ideal_scheduler->num_pending();
+ if ( nreqs > max_mrqs) {
+ max_mrqs = nreqs;
}
- dm->ave_mrqs += nreqs;
- dm->ave_mrqs_partial += nreqs;
+ ave_mrqs += nreqs;
+ ave_mrqs_partial += nreqs;
} else {
- if (dm->mrqq->length > dm->max_mrqs) {
- dm->max_mrqs = dm->mrqq->length;
+ if (mrqq->get_length() > max_mrqs) {
+ max_mrqs = mrqq->get_length();
}
- dm->ave_mrqs += dm->mrqq->length;
- dm->ave_mrqs_partial += dm->mrqq->length;
+ ave_mrqs += mrqq->get_length();
+ ave_mrqs_partial += mrqq->get_length();
}
- k=dm->nbk;
+ k=nbk;
// check if any bank is ready to issue a new read
- for (i=0;i<dm->nbk;i++) {
- j = (i + dm->prio) % dm->nbk;
- if (dm->bk[j]->mrq) { //if currently servicing a memory request
+ for (i=0;i<nbk;i++) {
+ j = (i + prio) % nbk;
+ if (bk[j]->mrq) { //if currently servicing a memory request
// correct row activated for a READ
- if ( !issued && !dm->CCDc && !dm->bk[j]->RCDc &&
- (dm->bk[j]->curr_row == dm->bk[j]->mrq->row) &&
- (dm->bk[j]->mrq->rw == READ) && (dm->WTRc == 0 ) &&
- (dm->bk[j]->state == BANK_ACTIVE) &&
- !dq_full(dm->rwq) ) {
- if (dm->rw==WRITE) {
- dm->rw=READ;
- dq_set_min_length(dm->rwq, dm->CL);
+ if ( !issued && !CCDc && !bk[j]->RCDc &&
+ (bk[j]->curr_row == bk[j]->mrq->row) &&
+ (bk[j]->mrq->rw == READ) && (WTRc == 0 ) &&
+ (bk[j]->state == BANK_ACTIVE) &&
+ !rwq->full() ) {
+ if (rw==WRITE) {
+ rw=READ;
+ rwq->set_min_length(CL,gpu_sim_cycle);
}
- dq_push(dm->rwq,(void*)dm->bk[j]->mrq); //only push when rwq empty?
- dm->bk[j]->mrq->txbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; //16 bytes
- dm->CCDc = dm->tCCD;
- dm->RTWc = dm->tRTW;
+ rwq->push(bk[j]->mrq,gpu_sim_cycle);
+ bk[j]->mrq->txbytes += BL * busW * gpu_n_mem_per_ctrlr; //16 bytes
+ CCDc = tCCD;
+ RTWc = tRTW;
issued = 1;
- dm->n_rd++;
- //printf("\tn_rd++ Bank: %d Row: %d Col: %d\n", j, dm->bk[j]->mrq->row, dm->bk[j]->mrq->col);
- dm->bwutil+= dm->BL/2;
- dm->bwutil_partial += dm->BL/2;
- dm->bk[j]->n_access++;
+ n_rd++;
+ bwutil+= BL/2;
+ bwutil_partial += BL/2;
+ bk[j]->n_access++;
#ifdef DRAM_VERIFY
PRINT_CYCLE=1;
printf("\tRD Bk:%d Row:%03x Col:%03x \n",
- j, dm->bk[j]->curr_row,
- dm->bk[j]->mrq->col+dm->bk[j]->mrq->txbytes-dm->BL*dm->busW);
+ j, bk[j]->curr_row,
+ bk[j]->mrq->col+bk[j]->mrq->txbytes-BL*busW);
#endif
// transfer done
- if ( !(dm->bk[j]->mrq->txbytes < dm->bk[j]->mrq->nbytes) ) {
- dm->bk[j]->mrq = NULL;
+ if ( !(bk[j]->mrq->txbytes < bk[j]->mrq->nbytes) ) {
+ bk[j]->mrq = NULL;
}
} else
// correct row activated for a WRITE
- if ( !issued && !dm->CCDc && !dm->bk[j]->RCDWRc &&
- (dm->bk[j]->curr_row == dm->bk[j]->mrq->row) &&
- (dm->bk[j]->mrq->rw == WRITE) && (dm->RTWc == 0 ) &&
- (dm->bk[j]->state == BANK_ACTIVE) &&
- !dq_full(dm->rwq) ) {
- if (dm->rw==READ) {
- dm->rw=WRITE;
- dq_set_min_length(dm->rwq, dm->WL);
+ if ( !issued && !CCDc && !bk[j]->RCDWRc &&
+ (bk[j]->curr_row == bk[j]->mrq->row) &&
+ (bk[j]->mrq->rw == WRITE) && (RTWc == 0 ) &&
+ (bk[j]->state == BANK_ACTIVE) &&
+ !rwq->full() ) {
+ if (rw==READ) {
+ rw=WRITE;
+ rwq->set_min_length(WL,gpu_sim_cycle);
}
- dq_push(dm->rwq,(void*)dm->bk[j]->mrq);
+ rwq->push(bk[j]->mrq,gpu_sim_cycle);
- dm->bk[j]->mrq->txbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; /*16 bytes*/
- dm->CCDc = dm->tCCD;
+ bk[j]->mrq->txbytes += BL * busW * gpu_n_mem_per_ctrlr; /*16 bytes*/
+ CCDc = tCCD;
issued = 1;
- dm->n_wr++;
- dm->bwutil+=2;
- dm->bwutil_partial += dm->BL/2;
+ n_wr++;
+ bwutil+=2;
+ bwutil_partial += BL/2;
#ifdef DRAM_VERIFY
PRINT_CYCLE=1;
printf("\tWR Bk:%d Row:%03x Col:%03x \n",
- j, dm->bk[j]->curr_row,
- dm->bk[j]->mrq->col+dm->bk[j]->mrq->txbytes-dm->BL*dm->busW);
+ j, bk[j]->curr_row,
+ bk[j]->mrq->col+bk[j]->mrq->txbytes-BL*busW);
#endif
// transfer done
- if ( !(dm->bk[j]->mrq->txbytes < dm->bk[j]->mrq->nbytes) ) {
- dm->bk[j]->mrq = NULL;
+ if ( !(bk[j]->mrq->txbytes < bk[j]->mrq->nbytes) ) {
+ bk[j]->mrq = NULL;
}
}
else
// bank is idle
- if ( !issued && !dm->RRDc &&
- (dm->bk[j]->state == BANK_IDLE) &&
- !dm->bk[j]->RPc && !dm->bk[j]->RCc ) {
+ if ( !issued && !RRDc &&
+ (bk[j]->state == BANK_IDLE) &&
+ !bk[j]->RPc && !bk[j]->RCc ) {
#ifdef DRAM_VERIFY
PRINT_CYCLE=1;
printf("\tACT BK:%d NewRow:%03x From:%03x \n",
- j,dm->bk[j]->mrq->row,dm->bk[j]->curr_row);
+ j,bk[j]->mrq->row,bk[j]->curr_row);
#endif
// activate the row with current memory request
- dm->bk[j]->curr_row = dm->bk[j]->mrq->row;
- dm->bk[j]->state = BANK_ACTIVE;
- dm->RRDc = dm->tRRD;
- dm->bk[j]->RCDc = dm->tRCD;
- dm->bk[j]->RCDWRc = dm->tRCDWR;
- dm->bk[j]->RASc = dm->tRAS;
- dm->bk[j]->RCc = dm->tRC;
- dm->prio = (j + 1) % dm->nbk;
+ bk[j]->curr_row = bk[j]->mrq->row;
+ bk[j]->state = BANK_ACTIVE;
+ RRDc = tRRD;
+ bk[j]->RCDc = tRCD;
+ bk[j]->RCDWRc = tRCDWR;
+ bk[j]->RASc = tRAS;
+ bk[j]->RCc = tRC;
+ prio = (j + 1) % nbk;
issued = 1;
- dm->n_act_partial++;
- dm->n_act++;
+ n_act_partial++;
+ n_act++;
}
else
// different row activated
if ( (!issued) &&
- (dm->bk[j]->curr_row != dm->bk[j]->mrq->row) &&
- (dm->bk[j]->state == BANK_ACTIVE) &&
- (!dm->bk[j]->RASc) ) {
- //printf("\tRASc: %d \n", dm->bk[j]->RASc);
+ (bk[j]->curr_row != bk[j]->mrq->row) &&
+ (bk[j]->state == BANK_ACTIVE) &&
+ (!bk[j]->RASc) ) {
// make the bank idle again
- dm->bk[j]->state = BANK_IDLE;
- dm->bk[j]->RPc = dm->tRP;
- dm->prio = (j + 1) % dm->nbk;
+ bk[j]->state = BANK_IDLE;
+ bk[j]->RPc = tRP;
+ prio = (j + 1) % nbk;
issued = 1;
- dm->n_pre++;
- dm->n_pre_partial++;
+ n_pre++;
+ n_pre_partial++;
#ifdef DRAM_VERIFY
PRINT_CYCLE=1;
- printf("\tPRE BK:%d Row:%03x \n", j,dm->bk[j]->curr_row);
- //printf("\tRASc: %d \n", dm->bk[j]->RASc);
+ printf("\tPRE BK:%d Row:%03x \n", j,bk[j]->curr_row);
#endif
}
} else {
- if (!dm->CCDc && !dm->RRDc && !dm->RTWc && !dm->WTRc && !dm->bk[j]->RCDc && !dm->bk[j]->RASc
- && !dm->bk[j]->RCc && !dm->bk[j]->RPc && !dm->bk[j]->RCDWRc) k--;
- dm->bk[i]->n_idle++;
+ if (!CCDc && !RRDc && !RTWc && !WTRc && !bk[j]->RCDc && !bk[j]->RASc
+ && !bk[j]->RCc && !bk[j]->RPc && !bk[j]->RCDWRc) k--;
+ bk[i]->n_idle++;
}
}
if (!issued) {
- dm->n_nop++;
- dm->n_nop_partial++;
+ n_nop++;
+ n_nop_partial++;
#ifdef DRAM_VIEWCMD
printf("\tNOP ");
#endif
}
if (k) {
- dm->n_activity++;
- dm->n_activity_partial++;
+ n_activity++;
+ n_activity_partial++;
}
- dm->n_cmd++;
- dm->n_cmd_partial++;
+ n_cmd++;
+ n_cmd_partial++;
// decrements counters once for each time dram_issueCMD is called
- DEC2ZERO(dm->RRDc);
- DEC2ZERO(dm->CCDc);
- DEC2ZERO(dm->RTWc);
- DEC2ZERO(dm->WTRc);
- for (j=0;j<dm->nbk;j++) {
- DEC2ZERO(dm->bk[j]->RCDc);
- DEC2ZERO(dm->bk[j]->RASc);
- DEC2ZERO(dm->bk[j]->RCc);
- DEC2ZERO(dm->bk[j]->RPc);
- DEC2ZERO(dm->bk[j]->RCDWRc);
+ DEC2ZERO(RRDc);
+ DEC2ZERO(CCDc);
+ DEC2ZERO(RTWc);
+ DEC2ZERO(WTRc);
+ for (j=0;j<nbk;j++) {
+ DEC2ZERO(bk[j]->RCDc);
+ DEC2ZERO(bk[j]->RASc);
+ DEC2ZERO(bk[j]->RCc);
+ DEC2ZERO(bk[j]->RPc);
+ DEC2ZERO(bk[j]->RCDWRc);
}
#ifdef DRAM_VISUALIZE
- dram_visualize(dm);
+ visualize();
#endif
}
//if mrq is being serviced by dram, gets popped after CL latency fulfilled
-void* dram_pop( dram_t *dm )
-{
+class mem_fetch* dram_t::pop()
+{
dram_req_t *mrq;
- void *data;
+ class mem_fetch *data;
unsigned dq_latency;
data = NULL;
- mrq = (dram_req_t*)dq_pop(dm->rwq);
+ mrq = rwq->pop(gpu_sim_cycle);
if (mrq) {
- // data = mrq->data;
#ifdef DRAM_VIEWCMD
printf("\tDQ: BK%d Row:%03x Col:%03x",
mrq->bk, mrq->row, mrq->col + mrq->dqbytes);
#endif
- mrq->dqbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; /*16 bytes*/
+ mrq->dqbytes += BL * busW * gpu_n_mem_per_ctrlr; /*16 bytes*/
if (mrq->dqbytes >= mrq->nbytes) {
-
- if (gpgpu_memlatency_stat) {
+ if (m_config->gpgpu_memlatency_stat) {
dq_latency = gpu_sim_cycle + gpu_tot_sim_cycle - mrq->timestamp;
- dq_lat_table[LOGB2(dq_latency)]++;
- if (dq_latency > max_dq_latency)
- max_dq_latency = dq_latency;
+ m_stats->dq_lat_table[LOGB2(dq_latency)]++;
+ if (dq_latency > m_stats->max_dq_latency)
+ m_stats->max_dq_latency = dq_latency;
}
data = mrq->data;
-
- free(mrq);
+ delete mrq;
}
}
#ifdef DRAM_VIEWCMD
@@ -483,17 +441,33 @@ void* dram_pop( dram_t *dm )
return data;
}
+void dram_t::returnq_push( class mem_fetch *mf, unsigned long long gpu_sim_cycle)
+{
+ returnq->push(mf,gpu_sim_cycle);
+}
+
+class mem_fetch* dram_t::returnq_pop( unsigned long long gpu_sim_cycle)
+{
+ return returnq->pop(gpu_sim_cycle);
+}
+
+class mem_fetch* dram_t::returnq_top()
+{
+ return returnq->top();
+}
+
+
// a hack to allow peeking into what memory request will be serviced.
-void* dram_top( dram_t *dm )
+class mem_fetch* dram_t::top()
{
dram_req_t *mrq;
- void *data;
+ class mem_fetch *data;
data = NULL;
- mrq = (dram_req_t*)dq_top(dm->rwq);
+ mrq = rwq->top();
if (mrq) {
// number of bytes returned from dram if this is ever popped
- unsigned tobe_dqbytes = mrq->dqbytes + dm->BL * dm->busW * gpu_n_mem_per_ctrlr;
+ unsigned tobe_dqbytes = mrq->dqbytes + BL * busW * gpu_n_mem_per_ctrlr;
if (tobe_dqbytes >= mrq->nbytes) {
data = mrq->data;
}
@@ -502,82 +476,112 @@ void* dram_top( dram_t *dm )
return data;
}
-void dram_print( dram_t* dm, FILE* simFile)
+void dram_t::print( FILE* simFile) const
{
unsigned i;
fprintf(simFile,"DRAM[%d]: %d bks, busW=%d BL=%d CL=%d, ",
- dm->id, dm->nbk, dm->busW, dm->BL, dm->CL );
+ id, nbk, busW, BL, CL );
fprintf(simFile,"tRRD=%d tCCD=%d, tRCD=%d tRAS=%d tRP=%d tRC=%d\n",
- dm->tCCD, dm->tRRD, dm->tRCD, dm->tRAS, dm->tRP, dm->tRC );
+ tCCD, tRRD, tRCD, tRAS, tRP, tRC );
fprintf(simFile,"n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_req=%d n_rd=%d n_write=%d bw_util=%.4g\n",
- dm->n_cmd, dm->n_nop, dm->n_act, dm->n_pre, dm->n_req, dm->n_rd, dm->n_wr,
- (float)dm->bwutil/dm->n_cmd);
+ n_cmd, n_nop, n_act, n_pre, n_req, n_rd, n_wr,
+ (float)bwutil/n_cmd);
fprintf(simFile,"n_activity=%d dram_eff=%.4g\n",
- dm->n_activity, (float)dm->bwutil/dm->n_activity);
- for (i=0;i<dm->nbk;i++) {
- fprintf(simFile, "bk%d: %da %di ",i,dm->bk[i]->n_access,dm->bk[i]->n_idle);
+ n_activity, (float)bwutil/n_activity);
+ for (i=0;i<nbk;i++) {
+ fprintf(simFile, "bk%d: %da %di ",i,bk[i]->n_access,bk[i]->n_idle);
}
fprintf(simFile, "\n");
fprintf(simFile, "dram_util_bins:");
- for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_util_bins[i]);
+ for (i=0;i<10;i++) fprintf(simFile, " %d", dram_util_bins[i]);
fprintf(simFile, "\ndram_eff_bins:");
- for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_eff_bins[i]);
+ for (i=0;i<10;i++) fprintf(simFile, " %d", dram_eff_bins[i]);
fprintf(simFile, "\n");
- /*
- {
- delay_data* mrq;
- mrq = dm->mrqq->head;
- while (mrq) {
- printf("%d",((dram_req_t*)mrq->data)->bk);
- mrq = mrq->next;
- }
- printf("\n");
- }
- */
- fprintf(simFile, "mrqq: max=%d avg=%g\n", dm->max_mrqs, (float)dm->ave_mrqs/dm->n_cmd);
+ fprintf(simFile, "mrqq: max=%d avg=%g\n", max_mrqs, (float)ave_mrqs/n_cmd);
}
-void dram_visualize( dram_t* dm )
+void dram_t::visualize() const
{
- unsigned i;
-
printf("RRDc=%d CCDc=%d mrqq.Length=%d rwq.Length=%d\n",
- dm->RRDc, dm->CCDc, dm->mrqq->length,dm->rwq->length);
- for (i=0;i<dm->nbk;i++) {
+ RRDc, CCDc, mrqq->get_length(),rwq->get_length());
+ for (unsigned i=0;i<nbk;i++) {
printf("BK%d: state=%c curr_row=%03x, %2d %2d %2d %2d %p ",
- i, dm->bk[i]->state, dm->bk[i]->curr_row,
- dm->bk[i]->RCDc, dm->bk[i]->RASc,
- dm->bk[i]->RPc, dm->bk[i]->RCc,
- dm->bk[i]->mrq );
- if (dm->bk[i]->mrq)
- printf("txf: %d %d", dm->bk[i]->mrq->nbytes, dm->bk[i]->mrq->txbytes);
+ i, bk[i]->state, bk[i]->curr_row,
+ bk[i]->RCDc, bk[i]->RASc,
+ bk[i]->RPc, bk[i]->RCc,
+ bk[i]->mrq );
+ if (bk[i]->mrq)
+ printf("txf: %d %d", bk[i]->mrq->nbytes, bk[i]->mrq->txbytes);
printf("\n");
}
- if ( dm->m_fast_ideal_scheduler ) {
- dump_fast_ideal_scheduler( dm );
- }
-
+ if ( m_fast_ideal_scheduler )
+ m_fast_ideal_scheduler->print(stdout);
}
-void dram_print_stat( dram_t* dm, FILE* simFile )
+void dram_t::print_stat( FILE* simFile )
{
- int i;
fprintf(simFile,"DRAM (%d): n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_req=%d n_rd=%d n_write=%d bw_util=%.4g ",
- dm->id, dm->n_cmd, dm->n_nop, dm->n_act, dm->n_pre, dm->n_req, dm->n_rd, dm->n_wr,
- (float)dm->bwutil/dm->n_cmd);
- fprintf(simFile, "mrqq: %d %.4g mrqsmax=%d ", dm->max_mrqs, (float)dm->ave_mrqs/dm->n_cmd, dm->max_mrqs_temp);
+ id, n_cmd, n_nop, n_act, n_pre, n_req, n_rd, n_wr,
+ (float)bwutil/n_cmd);
+ fprintf(simFile, "mrqq: %d %.4g mrqsmax=%d ", max_mrqs, (float)ave_mrqs/n_cmd, max_mrqs_temp);
fprintf(simFile, "\n");
fprintf(simFile, "dram_util_bins:");
- for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_util_bins[i]);
+ for (unsigned i=0;i<10;i++) fprintf(simFile, " %d", dram_util_bins[i]);
fprintf(simFile, "\ndram_eff_bins:");
- for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_eff_bins[i]);
+ for (unsigned i=0;i<10;i++) fprintf(simFile, " %d", dram_eff_bins[i]);
fprintf(simFile, "\n");
- dm->max_mrqs_temp = 0;
+ max_mrqs_temp = 0;
}
-
-unsigned dram_busy( dram_t* dm)
+void dram_t::queue_latency_log_dump( FILE *fp )
{
- return !dm->m_request_tracker.empty();
+ fprintf(fp,"(LOGB2)Latency DRAM[%d] ",id);
+ StatDisp(mrqq->get_lat_stat());
+ fprintf(fp,"(LOGB2)Latency DRAM[%d] ",id);
+ StatDisp(rwq->get_lat_stat());
+ dram_log(DUMPLOG);
}
+void dram_t::visualizer_print( gzFile visualizer_file )
+{
+ // dram specific statistics
+ gzprintf(visualizer_file,"dramncmd: %u %u\n",id, n_cmd_partial);
+ gzprintf(visualizer_file,"dramnop: %u %u\n",id,n_nop_partial);
+ gzprintf(visualizer_file,"dramnact: %u %u\n",id,n_act_partial);
+ gzprintf(visualizer_file,"dramnpre: %u %u\n",id,n_pre_partial);
+ gzprintf(visualizer_file,"dramnreq: %u %u\n",id,n_req_partial);
+ gzprintf(visualizer_file,"dramavemrqs: %u %u\n",id,
+ n_cmd_partial?(ave_mrqs_partial/n_cmd_partial ):0);
+
+ // utilization and efficiency
+ gzprintf(visualizer_file,"dramutil: %u %u\n",
+ id,n_cmd_partial?100*bwutil_partial/n_cmd_partial:0);
+ gzprintf(visualizer_file,"drameff: %u %u\n",
+ id,n_activity_partial?100*bwutil_partial/n_activity_partial:0);
+
+ // reset for next interval
+ bwutil_partial = 0;
+ n_activity_partial = 0;
+ ave_mrqs_partial = 0;
+ n_cmd_partial = 0;
+ n_nop_partial = 0;
+ n_act_partial = 0;
+ n_pre_partial = 0;
+ n_req_partial = 0;
+
+ // dram access type classification
+ for (unsigned j = 0; j < m_config->gpu_mem_n_bk; j++) {
+ gzprintf(visualizer_file,"dramglobal_acc_r: %u %u %u\n", id, j,
+ m_stats->mem_access_type_stats[GLOBAL_ACC_R][id][j]);
+ gzprintf(visualizer_file,"dramglobal_acc_w: %u %u %u\n", id, j,
+ m_stats->mem_access_type_stats[GLOBAL_ACC_W][id][j]);
+ gzprintf(visualizer_file,"dramlocal_acc_r: %u %u %u\n", id, j,
+ m_stats->mem_access_type_stats[LOCAL_ACC_R][id][j]);
+ gzprintf(visualizer_file,"dramlocal_acc_w: %u %u %u\n", id, j,
+ m_stats->mem_access_type_stats[LOCAL_ACC_W][id][j]);
+ gzprintf(visualizer_file,"dramconst_acc_r: %u %u %u\n", id, j,
+ m_stats->mem_access_type_stats[CONST_ACC_R][id][j]);
+ gzprintf(visualizer_file,"dramtexture_acc_r: %u %u %u\n", id, j,
+ m_stats->mem_access_type_stats[TEXTURE_ACC_R][id][j]);
+ }
+}
diff --git a/src/gpgpu-sim/dram.h b/src/gpgpu-sim/dram.h
index 34be319..68b2474 100644
--- a/src/gpgpu-sim/dram.h
+++ b/src/gpgpu-sim/dram.h
@@ -1,5 +1,5 @@
/*
- * dram.c
+ * dram.cc
*
* Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, George L. Yuan,
* Ivan Sham, Justin Kwong, Dan O'Connor and the
@@ -66,28 +66,24 @@
* Vancouver, BC V6T 1Z4
*/
-#include <stdio.h>
-#include <stdlib.h>
+#ifndef DRAM_H
+#define DRAM_H
#include "delayqueue.h"
#include "../cuda-sim/dram_callback.h"
#include <set>
-
-#ifndef DRAM_H
-#define DRAM_H
-
-#define FIFO_AGE_LIMIT 50 //used for both BANK_CONF and REALISTIC schedulers
-#define FIFO_NUM_WRITE_LIMIT 3 //used for both BANK_CONF and REALISTIC schedulers
-#define LOOKAHEAD_VALUE 10 //used for REALISTIC scheduler ONLY
-
-enum dram_ctrl_t {
- DRAM_FIFO=0,
- DRAM_IDEAL_FAST=1
-};
+#include <zlib.h>
+#include <stdio.h>
+#include <stdlib.h>
#define READ 'R' //define read and write states
#define WRITE 'W'
-typedef struct {
+#define BANK_IDLE 'I'
+#define BANK_ACTIVE 'A'
+
+struct dram_req_t
+{
+ dram_req_t( class mem_fetch *data );
unsigned int row;
unsigned int col;
unsigned int bk;
@@ -99,15 +95,12 @@ typedef struct {
unsigned char rw; //is the request a read or a write?
unsigned long long int addr;
unsigned int insertion_time;
- void* data;
-
+ class mem_fetch * data;
int cache_hits_waiting;
-} dram_req_t;
-
-#define BANK_IDLE 'I'
-#define BANK_ACTIVE 'A'
+};
-typedef struct {
+struct bank_t
+{
unsigned int RCDc;
unsigned int RCDWRc;
unsigned int RASc;
@@ -123,13 +116,45 @@ typedef struct {
unsigned int n_access;
unsigned int n_writes;
unsigned int n_idle;
-} bank_t;
+};
struct mem_fetch;
-typedef struct dram_timing {
+class dram_t
+{
+public:
+ dram_t( unsigned int parition_id, struct memory_config *config);
+
+ void set_stats( class memory_stats_t *stats ) {m_stats=stats;}
+
+ int full();
+ class mem_fetch* top();
+ void print( FILE* simFile ) const;
+ void visualize() const;
+ void print_stat( FILE* simFile );
+ unsigned int que_length() const;
+ bool returnq_full() const;
+ unsigned int queue_limit() const;
+ void visualizer_print( gzFile visualizer_file );
+
+ class mem_fetch* pop();
+ void returnq_push( class mem_fetch *mf, unsigned long long gpu_sim_cycle);
+ class mem_fetch* returnq_pop( unsigned long long gpu_sim_cycle);
+ class mem_fetch* returnq_top();
+ void push( class mem_fetch *data );
+ void issueCMD();
+ void queue_latency_log_dump( FILE *fp );
+ void dram_log (int task);
+
+ struct memory_partition_unit *m_memory_partition_unit;
unsigned int id;
+private:
+ void scheduler_fifo();
+ void fast_scheduler_ideal();
+
+ struct memory_config *m_config;
+
unsigned int tCCD; //column to column delay
unsigned int tRRD; //minimal time required between activation of rows in different banks
unsigned int tRCD; //row to column delay - time required to activate a row before a read
@@ -157,21 +182,17 @@ typedef struct dram_timing {
unsigned char rw; //was last request a read or write? (important for RTW, WTR)
unsigned int pending_writes;
- unsigned char realistic_scheduler_mode;
- delay_queue *rwq;
- delay_queue *mrqq;
+ fifo_pipeline<dram_req_t> *rwq;
+ fifo_pipeline<dram_req_t> *mrqq;
//buffer to hold packets when DRAM processing is over
//should be filled with dram clock and popped with l2or icnt clock
- delay_queue *returnq;
-
+ fifo_pipeline<mem_fetch> *returnq;
unsigned int dram_util_bins[10];
unsigned int dram_eff_bins[10];
unsigned int last_n_cmd, last_n_activity, last_bwutil;
- unsigned int queue_limit;
-
unsigned int n_cmd;
unsigned int n_activity;
unsigned int n_nop;
@@ -185,11 +206,8 @@ typedef struct dram_timing {
unsigned int bwutil;
unsigned int max_mrqs;
unsigned int ave_mrqs;
- unsigned char scheduler_type;
-
- void *m_fast_ideal_scheduler;
- void *m_L2cache;
+ class ideal_dram_scheduler* m_fast_ideal_scheduler;
unsigned int n_cmd_partial;
unsigned int n_activity_partial;
@@ -200,41 +218,10 @@ typedef struct dram_timing {
unsigned int ave_mrqs_partial;
unsigned int bwutil_partial;
- void * req_hist;
+ struct memory_stats_t *m_stats;
+ class Stats* mrqq_Dist; //memory request queue inside DRAM
- std::set<mem_fetch*> m_request_tracker;
-} dram_t;
-
-
-dram_t* dram_create( unsigned int id, unsigned int nbk,
- unsigned int tCCD, unsigned int tRRD,
- unsigned int tRCD, unsigned int tRAS,
- unsigned int tRP, unsigned int tRC,
- unsigned int CL, unsigned int WL,
- unsigned int BL, unsigned int tWTR,
- unsigned int busW, unsigned int queue_limit,
- unsigned char scheduler_type );
-void dram_free( dram_t *dm );
-int dram_full( dram_t *dm );
-void dram_push( dram_t *dm, unsigned int bank,
- unsigned int row, unsigned int col,
- unsigned int nbytes, unsigned int write,
- unsigned int wid, unsigned int sid, int cache_hits_waiting, unsigned long long addr,
- void *data );
-void scheduler_fifo(dram_t* dm);
-void dram_issueCMD (dram_t* dm);
-void* dram_pop( dram_t *dm );
-void* dram_top( dram_t *dm );
-unsigned dram_busy( dram_t *dm);
-void dram_print( dram_t* dm, FILE* simFile );
-void dram_visualize( dram_t* dm );
-void dram_print_stat( dram_t* dm, FILE* simFile );
-void fast_scheduler_ideal(dram_t* dm);
-void* alloc_fast_ideal_scheduler(dram_t *dm);
-void dump_fast_ideal_scheduler(dram_t *dm);
-unsigned fast_scheduler_queue_length(dram_t *dm);
-
-//supposed to return the current queue length for all memory scheduler types.
-unsigned int dram_que_length( dram_t *dm );
+ friend class ideal_dram_scheduler;
+};
#endif /*DRAM_H*/
diff --git a/src/gpgpu-sim/dram_sched.cc b/src/gpgpu-sim/dram_sched.cc
index e678042..1e36b05 100644
--- a/src/gpgpu-sim/dram_sched.cc
+++ b/src/gpgpu-sim/dram_sched.cc
@@ -170,21 +170,13 @@ void ideal_dram_scheduler::print( FILE *fp )
}
}
-void* alloc_fast_ideal_scheduler(dram_t *dm)
+void dram_t::fast_scheduler_ideal()
{
- return new ideal_dram_scheduler(dm);
-}
-
-void fast_scheduler_ideal(dram_t* dm)
-{
-
-
+ dram_t* dm=this;
unsigned mrq_latency;
- // replacement for scheduler_ideal()
-
- ideal_dram_scheduler *sched = reinterpret_cast<ideal_dram_scheduler*>( dm->m_fast_ideal_scheduler );
- while ( !dq_empty(dm->mrqq) && (!gpgpu_dram_sched_queue_size || sched->num_pending() < (unsigned) gpgpu_dram_sched_queue_size)) {
- dram_req_t *req = (dram_req_t*)dq_pop(dm->mrqq);
+ ideal_dram_scheduler *sched = dm->m_fast_ideal_scheduler;
+ while ( !dm->mrqq->empty() && (!m_config->gpgpu_dram_sched_queue_size || sched->num_pending() < m_config->gpgpu_dram_sched_queue_size)) {
+ dram_req_t *req = dm->mrqq->pop(gpu_sim_cycle);
sched->add_req(req);
}
@@ -199,12 +191,12 @@ void fast_scheduler_ideal(dram_t* dm)
if ( req ) {
dm->prio = (dm->prio+1)%dm->nbk;
dm->bk[b]->mrq = req;
- if (gpgpu_memlatency_stat) {
+ if (m_config->gpgpu_memlatency_stat) {
mrq_latency = gpu_sim_cycle + gpu_tot_sim_cycle - dm->bk[b]->mrq->timestamp;
dm->bk[b]->mrq->timestamp = gpu_tot_sim_cycle + gpu_sim_cycle;
- mrq_lat_table[LOGB2(mrq_latency)]++;
- if (mrq_latency > max_mrq_latency) {
- max_mrq_latency = mrq_latency;
+ m_stats->mrq_lat_table[LOGB2(mrq_latency)]++;
+ if (mrq_latency > m_stats->max_mrq_latency) {
+ m_stats->max_mrq_latency = mrq_latency;
}
}
@@ -213,24 +205,3 @@ void fast_scheduler_ideal(dram_t* dm)
}
}
}
-
-
-
-void dump_fast_ideal_scheduler( dram_t *dm )
-{
- ideal_dram_scheduler *sched = reinterpret_cast<ideal_dram_scheduler*>( dm->m_fast_ideal_scheduler );
- sched->print(stdout);
-}
-
-unsigned fast_scheduler_queue_length(dram_t *dm)
-{
- if (dm->m_fast_ideal_scheduler ) {
- ideal_dram_scheduler *sched = reinterpret_cast<ideal_dram_scheduler*>( dm->m_fast_ideal_scheduler );
- return sched->num_pending();
- } else {
- printf("fast_scheduler_queue_length(): Where did the scheduler go?\n");
- exit(1);
- }
-}
-
-
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index 013ca54..bfd8772 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -81,14 +81,21 @@ shd_cache_line_t* shd_cache_access_internal( shd_cache_t *cp,
unsigned int sim_cycle,
unsigned int real_access);
-shd_cache_t * shd_cache_create( char *name,
- unsigned int nset,
- unsigned int assoc,
- unsigned int line_sz,
- unsigned char policy,
+shd_cache_t * shd_cache_create( const char *name,
+ const char *opt,
unsigned int hit_latency,
unsigned long long int bank_mask,
- enum cache_write_policy wp) {
+ enum cache_write_policy wp)
+{
+ unsigned int nset;
+ unsigned int line_sz;
+ unsigned int assoc;
+ unsigned char policy;
+ int ntok = sscanf(opt,"%d:%d:%d:%c", &nset, &line_sz, &assoc, &policy);
+ if( ntok != 4 ) {
+ printf("GPGPU-Sim uArch: cache configuration string parsing error for cache %s\n", name);
+ abort();
+ }
shd_cache_t *cp;
unsigned int nlines;
@@ -130,10 +137,6 @@ shd_cache_t * shd_cache_create( char *name,
cp->prev_snapshot_miss = 0;
cp->prev_snapshot_merge_hit = 0;
-// printf("%s: %d(%x) x %d x %d(%x) %c, %d\n",
-// cp->name, cp->nset, cp->nset_log2, cp->assoc, cp->line_sz,
-// cp->line_sz_log2, cp->policy, nlines);
-
return cp;
}
@@ -203,142 +206,115 @@ shd_cache_line_t* shd_cache_access( shd_cache_t *cp,
unsigned char write,
unsigned int sim_cycle )
{
+ assert( cp->write_policy != write_back );
return shd_cache_access_internal(cp,addr,nbytes,write,sim_cycle,1/*this is a real access*/);
}
-shd_cache_t *test = NULL;
-enum cache_request_status shd_cache_access_wb( shd_cache_t *cp,
+enum cache_request_status shd_cache_access_new( shd_cache_t *cp,
unsigned long long int addr,
unsigned int nbytes,
unsigned char write,
unsigned int sim_cycle, address_type *wb_address)
{
- unsigned int i;
- unsigned int set;
- unsigned long long int tag;
- unsigned long long int packed_addr;
- shd_cache_line_t *pline;
-
- unsigned already_reserved = 0;
- unsigned all_reserved = 1;
- shd_cache_line_t *free_line = NULL;
+ unsigned long long int bank_addr; // offset within bank
+ bool all_reserved = true;
+ shd_cache_line_t *pending_line = NULL;
+ shd_cache_line_t *clean_line = NULL;
if (cp->bank_mask)
- packed_addr = addrdec_packbits(cp->bank_mask, addr, 64, 0);
+ bank_addr = addrdec_packbits(cp->bank_mask, addr, 64, 0);
else
- packed_addr = addr;
+ bank_addr = addr;
- set = (packed_addr >> cp->line_sz_log2) & ( (1<<cp->nset_log2) - 1 );
- tag = packed_addr >> (cp->line_sz_log2 + cp->nset_log2);
+ unsigned set = (bank_addr >> cp->line_sz_log2) & ( (1<<cp->nset_log2) - 1 );
+ unsigned long long tag = bank_addr >> (cp->line_sz_log2 + cp->nset_log2);
cp->access++;
shader_cache_access_log(cp->core_id, cp->type_id, 0);
- for (i=0; i<cp->assoc; i++) {
- pline = &(cp->lines[set*cp->assoc+i] );
- if (pline->tag == tag) {
- if (pline->status & RESERVED) {
- already_reserved = 1;
+ for (unsigned way=0; way<cp->assoc; way++) {
+ shd_cache_line_t *line = &(cp->lines[set*cp->assoc+way] );
+ if (line->tag == tag) {
+ if (line->status & RESERVED) {
+ pending_line = line;
break;
- } else if (pline->status & VALID) {
- //printf("Cache Hit! Addr=%08x Set=%x Way=%x Tag=%x\n", packed_addr, set, i, tag);
- pline->last_used = sim_cycle;
- if (write) {
- pline->status |= DIRTY;
- }
- //return pline;
- if (cp->write_policy == write_through) return HIT_W_WT;
+ } else if (line->status & VALID) {
+ line->last_used = sim_cycle;
+ if (write)
+ line->status |= DIRTY;
+ if (cp->write_policy == write_through)
+ return HIT_W_WT;
return HIT;
}
}
- if (!(pline->status & RESERVED)) {
- all_reserved = 0;
- if (!(pline->status & VALID)) {
- free_line = pline;
- }
+ if (!(line->status & RESERVED)) {
+ all_reserved = false;
+ if (!(line->status & VALID))
+ clean_line = line;
}
}
cp->miss++;
shader_cache_access_log(cp->core_id, cp->type_id, 1);
- if (already_reserved || cp->write_policy != write_back || write) {
- //not in cache yet, but no wb as place is reserved.
- //or wt caches never nead to worry about it (as do no_write caches)
- //or is a write
- if (already_reserved && write) {
- //write the data into the cache line, make it dirty
- //up to mshrs to save write mask to not overwrite this data when the read returns
- pline->status |= DIRTY;
- return WB_HIT_ON_MISS;
- } else if (already_reserved) {
+ if (pending_line || cp->write_policy != write_back || write) {
+ if (pending_line) {
+ if( write ) // write hit-under-miss (irrelevant whether write-back or write-through)
+ // - timing assumes a large enough write buffer in shader core that we never
+ // encounter a structural hazard
+ // - write buffer merged with returning cache block in zero cycles
+ pending_line->status |= DIRTY;
return WB_HIT_ON_MISS;
}
return MISS_NO_WB;
}
- //if not in cache, and a write back cache, and not already allocated, need to allocate a place for this request
+ // at this point: this must be a write back cache (and not a hit-under-miss)
+ assert( cp->write_policy == write_back );
- if (all_reserved) {
- //cannot service this request, because we can't garantee that we have room for the line when it comes back
+ if (all_reserved)
+ // cannot service this request, because we can't garantee that we have room for the line when it comes back
return RESERVATION_FAIL;
- }
-
- //printf("RESRV %d\n",tag);
- if (free_line) {
- //reserve fo this request
- free_line->status |= RESERVED;
- free_line->tag = tag;
- //no writeback
- return MISS_NO_WB;
+ if (clean_line) {
+ // found a clean line in the cache so, no need to do a writeback
+ clean_line->status |= RESERVED;
+ clean_line->tag = tag;
+ return MISS_NO_WB;
}
- // need to kick a line out to reserve a spot
- shd_cache_line_t *rline = NULL;
+ // no clean lines, need to kick a line out to reserve a spot
+ shd_cache_line_t *wb_line = NULL;
- for (i=0; i<cp->assoc; i++) {
- pline = &(cp->lines[set*cp->assoc+i] );
- if (pline->status & VALID && !(pline->status & RESERVED)) {
- if (!rline) {
- rline = pline; //select first available for ejection for later comparison
+ for (unsigned way=0; way<cp->assoc; way++) {
+ shd_cache_line_t *line = &(cp->lines[set*cp->assoc+way] );
+ if (line->status & VALID && !(line->status & RESERVED)) {
+ if (!wb_line) {
+ wb_line = line;
continue;
}
switch (cp->policy) {
case LRU:
- if (pline->last_used < rline->last_used)
- rline = pline;
+ if (line->last_used < wb_line->last_used)
+ wb_line = line;
break;
case FIFO:
- if (pline->fetch_time < rline->fetch_time)
- rline = pline;
+ if (line->fetch_time < wb_line->fetch_time)
+ wb_line = line;
break;
default:
- rline = pline; //pick one, ie. the last valied one.
+ abort();
}
}
}
- assert(rline); //ensure we actually found one.
-
- unsigned needs_wb = (rline->status & (DIRTY|VALID)) == (DIRTY|VALID);
- /* Set the replaced cache line address */
- if (needs_wb) {
- *wb_address = rline->addr;
- }
+ assert(wb_line); // should always find a line
+ assert((wb_line->status & (DIRTY|VALID)) == (DIRTY|VALID)); // should be dirty (or we would have found a clean line earlier)
- /* reserve this new line */
- rline->status |= RESERVED;
- rline->status &= ~VALID;
- rline->status &= ~DIRTY;
- rline->tag = tag;
+ // reserve line
+ wb_line->status = RESERVED;
+ wb_line->tag = tag;
+ *wb_address = wb_line->addr;
- /* printf("Fetching! Addr=%08x ReplAddr=%08x(%d) Set=%x Tag=%x\n",
- packed_addr, repl_addr, nofreeslot, set, tag);
- */
- if (needs_wb) {
- return MISS_W_WB;
- } else {
- return MISS_NO_WB;
- }
+ return MISS_W_WB;
}
shd_cache_line_t* shd_cache_probe( shd_cache_t *cp,
@@ -439,9 +415,6 @@ unsigned long long int shd_cache_fill( shd_cache_t *cp,
}
}
- //if (cline) printf("FOUND %d\n",tag);
- //else printf("UNFOUND!!! %d\n", tag);
-
if (!cline) printf("----!!! about to abort - this probably happened because global memory msrh merging is not enabled with a writeback cache !!!----\n");
assert(cline); //error if it doesn't have a reserved space
@@ -518,9 +491,6 @@ unsigned long long int shd_cache_fill( shd_cache_t *cp,
cline->last_used = sim_cycle;
cline->fetch_time = sim_cycle;
-/* printf("Fetching! Addr=%08x ReplAddr=%08x(%d) Set=%x Tag=%x\n",
- packed_addr, repl_addr, nofreeslot, set, tag);
- */
return repl_addr;
}
@@ -529,7 +499,8 @@ void shd_cache_mergehit( shd_cache_t *cp, unsigned long long int addr )
cp->merge_hit += 1;
}
-void shd_cache_print( shd_cache_t *cp, FILE *stream) {
+void shd_cache_print( const shd_cache_t *cp, FILE *stream, unsigned &total_access, unsigned &total_misses )
+{
fprintf( stream, "Cache %s:\t", cp->name);
fprintf( stream, "Size = %d B (%d Set x %d-way x %d byte line)\n",
cp->line_sz * cp->nset * cp->assoc,
@@ -537,67 +508,6 @@ void shd_cache_print( shd_cache_t *cp, FILE *stream) {
fprintf( stream, "\t\tAccess = %d, Miss = %d (%.3g), -MgHts = %d (%.3g)\n",
cp->access, cp->miss, (float) cp->miss / cp->access,
cp->miss - cp->merge_hit, (float) (cp->miss - cp->merge_hit) / cp->access);
+ total_misses+=cp->miss;
+ total_access+=cp->access;
}
-
-#ifdef UNIT_TEST
-
-int main() {
- shd_cache_t *cp[3];
- unsigned int addr, i;
- unsigned int cachenum;
- unsigned int sim_cycle;
-
- unsigned int test_addrs[8] = { 0x100, 0x200, 0x300, 0x400,
- 0x104, 0x204, 0x500, 0x100};
- unsigned int repl_addr[8] = {0,0,0,0,0,0,0,0};
- unsigned int rdwr[8] = {0,1,0,0,0,0,0,0};
-
- sim_cycle = 0;
- cp[0] = shd_cache_create ("cp1", 16, 4, 16, LRU, 1);
- cp[1] = shd_cache_create ("cp2", 16, 4, 16, FIFO, 1);
-
- for (cachenum = 0; cachenum<2; cachenum++)
- for (i=0; i<8; i++) {
- if ( !shd_cache_access(cp[cachenum], test_addrs[i], 4, rdwr[i], sim_cycle) ) {
- repl_addr[i] = shd_cache_fill(cp[cachenum], test_addrs[i], sim_cycle);
- shd_cache_access(cp[cachenum], test_addrs[i], 4, rdwr[i], sim_cycle);
- }
- sim_cycle++;
- }
-
- printf("replaced address:");
- for (i=0; i<8; i++) {
- printf("0x%x ", repl_addr[i]);
- }
- printf("\n");
- shd_cache_print(cp[0],stdout);
- shd_cache_print(cp[1],stdout);
-
- shd_cache_fill(cp[0], 0x104b3ecb0, sim_cycle);
- printf("Accessing 64-bit address tag: %d\n",
- shd_cache_access(cp[0], 0x104b3ecb2, 4, 0, sim_cycle));
- printf("Accessing 64-bit address tag: %d\n",
- shd_cache_access(cp[0], 0x103433330, 4, 0, sim_cycle));
-
-
- shd_set_coherency_policy(2);
- cp[2] = shd_cache_create("cp2", 16, 4, 16, LRU, 1);
- shd_cache_fill(cp[2], 0x12345000, 0);
- shd_cache_access(cp[2], 0x12345000, 4, 1, 0);
- shd_cache_access(cp[2], 0x12345004, 4, 0, 0);
- shd_cache_access(cp[2], 0x12345008, 4, 0, 0);
- shd_cache_access(cp[2], 0x1234500C, 4, 1, 0);
- printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0xf,
- shd_cache_linedirty(cp[2], 0x12345000, 0xf), 1 );
- printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x6,
- shd_cache_linedirty(cp[2], 0x12345000, 0x6), 0 );
- printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x1,
- shd_cache_linedirty(cp[2], 0x12345000, 0x1), 1 );
- printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x8,
- shd_cache_linedirty(cp[2], 0x12345000, 0x8), 1 );
- printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x9,
- shd_cache_linedirty(cp[2], 0x12345000, 0x9), 1 );
-
-}
-
-#endif
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index d07d1e1..3b4bf73 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -71,22 +71,22 @@
#ifndef GPU_CACHE_H
#define GPU_CACHE_H
-#define VALID 0x01
-#define DIRTY 0x02
-#define RESERVED 0x04
+#define VALID 0x01 // block is valid (and present in cache)
+#define DIRTY 0x02 // block is dirty
+#define RESERVED 0x04 // there is an outstanding request for this block, but it has not returned yet
enum cache_request_status {
HIT,
- HIT_W_WT, /* Hit, but write through cache, still needs to send to memory */
- MISS_NO_WB, /* miss, but witeback not necessary*/
- MISS_W_WB, /* miss, must do writeback */
- WB_HIT_ON_MISS, /* request hit on a reservation in wb cache*/
+ HIT_W_WT, // Hit, but write through cache, still needs to send to memory
+ MISS_NO_WB, // miss, but witeback not necessary
+ MISS_W_WB, // miss, must do writeback
+ WB_HIT_ON_MISS, // request hit on a reservation in wb cache
RESERVATION_FAIL,
NUM_CACHE_REQUEST_STATUS
};
-typedef struct {
+struct shd_cache_line_t {
unsigned long long int tag;
unsigned long long int addr;
unsigned int set;
@@ -94,7 +94,7 @@ typedef struct {
unsigned int fetch_time;
unsigned int last_used;
unsigned char status; /* valid, dirty... etc */
-} shd_cache_line_t;
+};
#define LRU 'L'
@@ -107,7 +107,7 @@ enum cache_write_policy{
write_through //reservation based, use much handle reservation full error.
};
-typedef struct {
+struct shd_cache_t {
char *name;
@@ -135,13 +135,10 @@ typedef struct {
unsigned long long int bank_mask;
-} shd_cache_t;
+};
-shd_cache_t * shd_cache_create( char *name,
- unsigned int nset,
- unsigned int assoc,
- unsigned int line_sz,
- unsigned char policy,
+shd_cache_t * shd_cache_create( const char *name,
+ const char *opt,
unsigned int hit_latency,
unsigned long long int bank_mask,
enum cache_write_policy wp);
@@ -151,15 +148,14 @@ void shd_cache_destroy( shd_cache_t* cp );
// hook up with shader core logger
void shd_cache_bind_logger(shd_cache_t* cp, int core_id, int type_id);
-//depercated, use _wb
+// depricated use shd_cache_access_new
shd_cache_line_t* shd_cache_access( shd_cache_t *cp,
unsigned long long int addr,
unsigned int nbytes,
unsigned char write,
unsigned int sim_cycle );
-//cache check checks for wb and forwards information over.
-enum cache_request_status shd_cache_access_wb( shd_cache_t *cp,
+enum cache_request_status shd_cache_access_new( shd_cache_t *cp,
unsigned long long int addr,
unsigned int nbytes,
unsigned char write,
@@ -185,7 +181,7 @@ unsigned long long int L2_shd_cache_fill( shd_cache_t *cp,
unsigned long long int addr,
unsigned int sim_cycle );
-void shd_cache_print( shd_cache_t *cp, FILE *stream);
+void shd_cache_print( const shd_cache_t *cp, FILE *stream, unsigned &total_access, unsigned &total_misses );
float shd_cache_windowed_cache_miss_rate(shd_cache_t*, int);
void shd_cache_new_window(shd_cache_t*);
diff --git a/src/gpgpu-sim/gpu-misc.h b/src/gpgpu-sim/gpu-misc.h
index 3b3cb4c..ffe316b 100644
--- a/src/gpgpu-sim/gpu-misc.h
+++ b/src/gpgpu-sim/gpu-misc.h
@@ -70,9 +70,9 @@
#define CONSTC 100
#define DCACHE 200
#define TEXTC 300
-#define SHD_CACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->L1cache->line_sz - 1)))
-#define SHD_TEXCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->L1texcache->line_sz - 1)))
-#define SHD_CONSTCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->L1constcache->line_sz - 1)))
+#define SHD_CACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->m_L1D->line_sz - 1)))
+#define SHD_TEXCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->m_L1T->line_sz - 1)))
+#define SHD_CONSTCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->m_L1C->line_sz - 1)))
#define CACHE_TAG_OF(x,cache) ((x) & (~((unsigned long long int)cache->line_sz - 1)))
#define CACHE_TAG_OF_64(x) ((x) & (~((unsigned long long int)64 - 1)))
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index b5527e1..8114b9e 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -91,18 +91,19 @@
#include "../cuda-sim/ptx-stats.h"
#include "../intersim/statwraper.h"
+#include "../intersim/interconnect_interface.h"
#include "../abstract_hardware_model.h"
#include "../debug.h"
#include "../gpgpusim_entrypoint.h"
#include "../cuda-sim/cuda-sim.h"
#include "mem_latency_stat.h"
+#include "visualizer.h"
+#include "stats.h"
#include <stdio.h>
#include <string.h>
-#include <queue>
-
#define MAX(a,b) (((a)>(b))?(a):(b))
bool g_interactive_debugger_enabled=false;
@@ -115,13 +116,10 @@ unsigned freed_L2write_mfs = 0;
unsigned freed_dummy_read_mfs = 0;
unsigned long long gpu_sim_cycle = 0;
unsigned long long gpu_sim_insn = 0;
-unsigned long long gpu_sim_insn_no_ld_const = 0;
unsigned long long gpu_sim_prev_insn = 0;
-unsigned long long gpu_sim_insn_last_update = 0;
unsigned long long gpu_tot_sim_cycle = 0;
unsigned long long gpu_tot_sim_insn = 0;
unsigned long long gpu_last_sim_cycle = 0;
-unsigned long long gpu_completed_thread = 0;
unsigned long long gpu_tot_issued_cta = 0;
unsigned long long gpu_tot_completed_thread = 0;
@@ -130,27 +128,17 @@ unsigned int **num_activates; //num_activates[dram chip id][bank id]
unsigned int **row_access; //row_access[dram chip id][bank id]
unsigned int **max_conc_access2samerow; //max_conc_access2samerow[dram chip id][bank id]
unsigned int **max_servicetime2samerow; //max_servicetime2samerow[dram chip id][bank id]
-unsigned int L1_read_miss = 0;
-unsigned int L1_write_miss = 0;
-unsigned int L1_write_hit_on_miss = 0;
-unsigned int L1_writeback = 0;
-unsigned int L1_texture_miss = 0;
-unsigned int L1_const_miss = 0;
unsigned int gpgpu_n_sent_writes = 0;
unsigned int gpgpu_n_processed_writes = 0;
-unsigned int *max_return_queue_length;
// performance counter for stalls due to congestion.
-unsigned int gpu_stall_shd_mem = 0;
unsigned int gpu_stall_wr_back = 0;
unsigned int gpu_stall_dramfull = 0;
unsigned int gpu_stall_icnt2sh = 0;
-unsigned int gpu_stall_by_MSHRwb = 0;
//shader cannot send to icnt because icnt buffer is full
//Note: it is accumulative for all shaders and is never reset
//so it might increase 8 times in a cycle if we have 8 shaders
-unsigned int gpu_stall_sh2icnt = 0;
char *gpgpu_runtime_stat;
int gpu_stat_sample_freq = 10000;
int gpu_runtime_stat_flag = 0;
@@ -160,7 +148,6 @@ unsigned long long gpu_max_insn = 0;
int gpu_deadlock = 0;
unsigned g_next_mf_request_uid = 1;
static unsigned long long last_gpu_sim_insn = 0;
-int g_nthreads_issued;
int g_total_cta_left;
// GPGPU-Sim timing model options
@@ -168,34 +155,12 @@ int gpu_max_cycle_opt;
int gpu_max_insn_opt;
int gpu_max_cta_opt;
bool gpu_deadlock_detect;
-int gpgpu_simd_model;
-enum dram_ctrl_t gpgpu_dram_scheduler;
-bool gpgpu_no_dl1;
-char *gpgpu_cache_texl1_opt;
-char *gpgpu_cache_constl1_opt;
-char *gpgpu_cache_dl1_opt;
-char *gpgpu_cache_dl2_opt;
-int gpgpu_partial_write_mask;
-bool gpgpu_perfect_mem;
char *gpgpu_shader_core_pipeline_opt;
-unsigned int gpgpu_dram_buswidth;
-unsigned int gpgpu_dram_burst_length;
int gpgpu_dram_sched_queue_size;
-char *gpgpu_dram_timing_opt;
bool gpgpu_flush_cache;
int gpgpu_mem_address_mask;
int gpgpu_cflog_interval;
-void ptx_dump_regs( void *thd );
-unsigned ptx_kernel_program_size();
-void visualizer_printstat();
-void time_vector_create(int ld_size,int st_size);
-void time_vector_print(void);
-void time_vector_update(unsigned int uid,int slot ,long int cycle,int type);
-void node_req_hist_clear(void *p);
-void node_req_hist_dump(void *p);
-void node_req_hist_update(void * p,int node, long long cycle);
-
/* Defining Clock Domains
basically just the ratio is important */
@@ -204,114 +169,34 @@ basically just the ratio is important */
#define DRAM 0x04
#define ICNT 0x08
-double core_time=0;
-double icnt_time=0;
-double dram_time=0;
-double l2_time=0;
-
-double core_freq=2 MhZ;
-double icnt_freq=2 MhZ;
-double dram_freq=2 MhZ;
-double l2_freq=2 MhZ;
-
-double core_period = 1 /( 2 MhZ);
-double icnt_period = 1 /( 2 MhZ);
-double dram_period = 1 /( 2 MhZ);
-double l2_period = 1 / (2 MhZ);
char * gpgpu_clock_domains;
/* GPU uArch parameters */
-unsigned int gpu_n_mem;
-unsigned int gpu_mem_n_bk;
unsigned int gpu_n_mem_per_ctrlr;
-unsigned int gpu_n_shader;
-int gpu_concentration;
int gpu_n_tpc;
-unsigned int gpu_n_mshr_per_shader;
-unsigned int gpu_n_thread_per_shader;
-unsigned int gpu_n_warp_per_shader;
-unsigned int gpu_n_mshr_per_thread = 1;
-bool gpgpu_reg_bankconflict;
-bool gpgpu_operand_collector;
-int gpgpu_operand_collector_num_units;
-int gpgpu_operand_collector_num_units_sfu;
-unsigned int gpgpu_pre_mem_stages;
-bool gpgpu_no_divg_load;
char *gpgpu_dwf_hw_opt;
bool gpgpu_thread_swizzling;
-bool gpgpu_strict_simd_wrbk;
-int pdom_sched_type;
-int n_pdom_sc_orig_stat = 0; //the selected pdom schedular is used
-int n_pdom_sc_single_stat = 0; //only a single warp is ready to go in that cycle.
-int *num_warps_issuable;
-int *num_warps_issuable_pershader;
-bool gpgpu_cuda_sim;
-bool gpgpu_spread_blocks_across_cores;
-bool gpgpu_stall_on_use;
-shader_core_ctx_t **sc;
-dram_t **dram;
-unsigned int common_clock = 0;
unsigned int more_thread = 1;
-unsigned int warp_conflict_at_writeback = 0;
-unsigned int gpgpu_commit_pc_beyond_two = 0;
-bool gpgpu_cache_wt_through;
-
-//memory access classification
-int gpgpu_n_mem_read_local = 0;
-int gpgpu_n_mem_write_local = 0;
-int gpgpu_n_mem_texture = 0;
-int gpgpu_n_mem_const = 0;
-int gpgpu_n_mem_read_global = 0;
-int gpgpu_n_mem_write_global = 0;
#define MEM_LATENCY_STAT_IMPL
#include "mem_latency_stat.h"
-unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid );
-unsigned char fq_push(unsigned long long int addr, int bsize, unsigned char write, partial_write_mask_t partial_write_mask,
- int sid, int wid, mshr_entry* mshr, int cache_hits_waiting,
- enum mem_access_type mem_acc, address_type pc);
-int issue_mf_from_fq(mem_fetch_t *mf);
-unsigned char single_check_icnt_has_buffer(int chip, int sid, unsigned char is_write );
-unsigned char fq_pop(int tpc_id);
-void fill_shd_L1_with_new_line(shader_core_ctx_t * sc, mem_fetch_t * mf);
-
-void set_param_gpgpu_num_shaders(int num_shaders);
-unsigned ptx_sim_grid_size();
-void icnt_init_grid();
-void interconnect_stats();
-void icnt_overal_stat();
-void gpu_sim_loop( int grid_num );
-void print_shader_cycle_distro( FILE *fout ) ;
-void find_reconvergence_points();
-void dwf_process_reconv_pts();
-
int g_ptx_inst_debug_to_file;
char* g_ptx_inst_debug_file;
int g_ptx_inst_debug_thread_uid;
-#define CREATELOG 111
-#define SAMPLELOG 222
-#define DUMPLOG 333
-void L2c_log(int task);
-void dram_log(int task);
-
-// DRAM delay queue and memory_fetch container
-// A delay queue for each mem - vector of queues
-struct dram_delay_t{
- unsigned long long ready_cycle;
- mem_fetch_t* mf;
-};
-std::vector< std::queue<dram_delay_t> > dram_delay_queues;
+int g_ptx_convert_to_ptxplus;
+int g_ptx_save_converted_ptxplus;
void visualizer_options(option_parser_t opp);
-void gpu_reg_options(option_parser_t opp)
+
+void gpgpu_sim::reg_options(option_parser_t opp)
{
- option_parser_register(opp, "-gpgpu_simd_model", OPT_INT32, &gpgpu_simd_model,
+ option_parser_register(opp, "-gpgpu_simd_model", OPT_INT32, &m_shader_config->model,
"0 = no recombination, 1 = post-dominator, 2 = MIMD, 3 = dynamic warp formation", "0");
- option_parser_register(opp, "-gpgpu_dram_scheduler", OPT_INT32, &gpgpu_dram_scheduler,
- "0 = fifo (default), 1 = fast ideal", "0");
+ option_parser_register(opp, "-gpgpu_dram_scheduler", OPT_INT32, &m_memory_config->scheduler_type,
+ "0 = fifo, 1 = FR-FCFS (defaul)", "1");
option_parser_register(opp, "-gpgpu_max_cycle", OPT_INT32, &gpu_max_cycle_opt,
"terminates gpu simulation early (0 = no limit)",
@@ -323,46 +208,54 @@ void gpu_reg_options(option_parser_t opp)
"terminates gpu simulation early (0 = no limit)",
"0");
- option_parser_register(opp, "-gpgpu_tex_cache:l1", OPT_CSTR, &gpgpu_cache_texl1_opt,
+ option_parser_register(opp, "-gpgpu_tex_cache:l1", OPT_CSTR, &m_shader_config->gpgpu_cache_texl1_opt,
"per-shader L1 texture cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}",
"512:64:2:L");
- option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &gpgpu_cache_constl1_opt,
+ option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &m_shader_config->gpgpu_cache_constl1_opt,
"per-shader L1 constant memory cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}",
"64:64:2:L");
- option_parser_register(opp, "-gpgpu_no_dl1", OPT_BOOL, &gpgpu_no_dl1,
+ option_parser_register(opp, "-gpgpu_no_dl1", OPT_BOOL, &m_shader_config->gpgpu_no_dl1,
"no dl1 cache (voids -gpgpu_cache:dl1 option)",
"0");
- option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &gpgpu_cache_dl1_opt,
+ option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &m_shader_config->gpgpu_cache_dl1_opt,
"shader L1 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}",
"256:128:1:L");
- option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &gpgpu_cache_dl2_opt,
+ option_parser_register(opp, "-gpgpu_cache:il1", OPT_CSTR, &m_shader_config->gpgpu_cache_il1_opt,
+ "shader L1 instruction cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}",
+ "4:256:4:L");
+
+ option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &m_memory_config->gpgpu_cache_dl2_opt,
"unified banked L2 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}; disabled by default",
NULL);
- option_parser_register(opp, "-gpgpu_perfect_mem", OPT_BOOL, &gpgpu_perfect_mem,
+ option_parser_register(opp, "-gpgpu_perfect_mem", OPT_BOOL, &m_shader_config->gpgpu_perfect_mem,
"enable perfect memory mode (no cache miss)",
"0");
+ option_parser_register(opp, "-gpgpu_sm_uarch", OPT_CSTR, &m_shader_config->pipeline_model,
+ "shader core uarch model [GPGPUSIM_ORIG,GT200] (default=GPGPUSIM_ORIG)",
+ "GPGPUSIM_ORIG");
+
option_parser_register(opp, "-gpgpu_shader_core_pipeline", OPT_CSTR, &gpgpu_shader_core_pipeline_opt,
"shader core pipeline config, i.e., {<nthread>:<warpsize>:<pipe_simd_width>}",
"256:32:32");
- option_parser_register(opp, "-gpgpu_shader_registers", OPT_UINT32, &gpgpu_shader_registers,
+ option_parser_register(opp, "-gpgpu_shader_registers", OPT_UINT32, &m_shader_config->gpgpu_shader_registers,
"Number of registers per shader core. Limits number of concurrent CTAs. (default 8192)",
"8192");
- option_parser_register(opp, "-gpgpu_shader_cta", OPT_UINT32, &gpgpu_shader_cta,
+ option_parser_register(opp, "-gpgpu_shader_cta", OPT_UINT32, &m_shader_config->max_cta_per_core,
"Maximum number of concurrent CTAs in shader (default 8)",
"8");
- option_parser_register(opp, "-gpgpu_n_shader", OPT_UINT32, &gpu_n_shader,
+ option_parser_register(opp, "-gpgpu_n_shader", OPT_UINT32, &m_n_shader,
"number of shaders in gpu",
"8");
- option_parser_register(opp, "-gpgpu_n_mem", OPT_UINT32, &gpu_n_mem,
+ option_parser_register(opp, "-gpgpu_n_mem", OPT_UINT32, &m_n_mem,
"number of memory modules (e.g. memory controllers) in gpu",
"8");
option_parser_register(opp, "-gpgpu_n_mem_per_ctrlr", OPT_UINT32, &gpu_n_mem_per_ctrlr,
@@ -376,39 +269,39 @@ void gpu_reg_options(option_parser_t opp)
"DWF scheduling heuristic: 0 = majority, 1 = minority, 2 = timestamp, 3 = pdom priority, 4 = pc-based, 5 = max-heap",
"0");
- option_parser_register(opp, "-gpgpu_reg_bankconflict", OPT_BOOL, &gpgpu_reg_bankconflict,
- "Check for bank conflict in the pipeline",
+ 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, &gpgpu_memlatency_stat,
+ 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");
- option_parser_register(opp, "-gpu_n_mshr_per_shader", OPT_UINT32, &gpu_n_mshr_per_shader,
+ option_parser_register(opp, "-gpu_n_mshr_per_shader", OPT_UINT32, &m_shader_config->n_mshr_per_shader,
"Number of MSHRs per shader",
"64");
- option_parser_register(opp, "-gpgpu_interwarp_mshr_merge", OPT_INT32, &gpgpu_interwarp_mshr_merge,
+ option_parser_register(opp, "-gpgpu_interwarp_mshr_merge", OPT_INT32, &m_shader_config->gpgpu_interwarp_mshr_merge,
"interwarp coalescing",
"0");
- option_parser_register(opp, "-gpgpu_dram_sched_queue_size", OPT_INT32, &gpgpu_dram_sched_queue_size,
+ option_parser_register(opp, "-gpgpu_dram_sched_queue_size", OPT_INT32, &m_memory_config->gpgpu_dram_sched_queue_size,
"0 = unlimited (default); # entries per chip",
"0");
- option_parser_register(opp, "-gpgpu_dram_buswidth", OPT_UINT32, &gpgpu_dram_buswidth,
+ option_parser_register(opp, "-gpgpu_dram_buswidth", OPT_UINT32, &m_memory_config->gpgpu_dram_buswidth,
"default = 4 bytes (8 bytes per cycle at DDR)",
"4");
- option_parser_register(opp, "-gpgpu_dram_burst_length", OPT_UINT32, &gpgpu_dram_burst_length,
+ option_parser_register(opp, "-gpgpu_dram_burst_length", OPT_UINT32, &m_memory_config->gpgpu_dram_burst_length,
"Burst length of each DRAM request (default = 4 DDR cycle)",
"4");
- option_parser_register(opp, "-gpgpu_dram_timing_opt", OPT_CSTR, &gpgpu_dram_timing_opt,
+ option_parser_register(opp, "-gpgpu_dram_timing_opt", OPT_CSTR, &m_memory_config->gpgpu_dram_timing_opt,
"DRAM timing parameters = {nbk:tCCD:tRRD:tRCD:tRAS:tRP:tRC:CL:WL:tWTR}",
"4:2:8:12:21:13:34:9:4:5");
@@ -421,13 +314,13 @@ void gpu_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, &gpgpu_pre_mem_stages,
+ 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, &gpgpu_no_divg_load,
- "Don't allow divergence on load",
- "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}",
@@ -437,23 +330,15 @@ void gpu_reg_options(option_parser_t opp)
"Thread Swizzling (1=on, 0=off)",
"0");
- option_parser_register(opp, "-gpgpu_strict_simd_wrbk", OPT_BOOL, &gpgpu_strict_simd_wrbk,
- "Applying Strick SIMD WriteBack Stage (1=on, 0=off)",
- "0");
-
- option_parser_register(opp, "-gpgpu_shmem_size", OPT_UINT32, &gpgpu_shmem_size,
+ 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");
- option_parser_register(opp, "-gpgpu_shmem_bkconflict", OPT_BOOL, &gpgpu_shmem_bkconflict,
- "Turn on bank conflict check for shared memory",
- "0");
-
- option_parser_register(opp, "-gpgpu_shmem_pipe_speedup", OPT_INT32, &gpgpu_shmem_pipe_speedup,
+ option_parser_register(opp, "-gpgpu_shmem_pipe_speedup", OPT_INT32, &m_shader_config->gpgpu_shmem_pipe_speedup,
"Number of groups each warp is divided for shared memory bank conflict check",
"2");
- option_parser_register(opp, "-gpgpu_cache_wt_through", OPT_BOOL, &gpgpu_cache_wt_through,
+ option_parser_register(opp, "-gpgpu_cache_wt_through", OPT_BOOL, &m_shader_config->gpgpu_cache_wt_through,
"L1 cache become write through (1=on, 0=off)",
"0");
@@ -461,36 +346,24 @@ void gpu_reg_options(option_parser_t opp)
"Stop the simulation at deadlock (1=on (default), 0=off)",
"1");
- option_parser_register(opp, "-gpgpu_cache_bkconflict", OPT_BOOL, &gpgpu_cache_bkconflict,
- "Turn on bank conflict check for L1 cache access",
- "0");
-
- option_parser_register(opp, "-gpgpu_n_cache_bank", OPT_INT32, &gpgpu_n_cache_bank,
+ option_parser_register(opp, "-gpgpu_n_cache_bank", OPT_INT32, &m_shader_config->gpgpu_n_cache_bank,
"Number of banks in L1 cache, also for memory coalescing stall",
"1");
- option_parser_register(opp, "-gpgpu_warpdistro_shader", OPT_INT32, &gpgpu_warpdistro_shader,
+ option_parser_register(opp, "-gpgpu_warpdistro_shader", OPT_INT32, &m_shader_config->gpgpu_warpdistro_shader,
"Specify which shader core to collect the warp size distribution from",
"-1");
- option_parser_register(opp, "-gpgpu_pdom_sched_type", OPT_INT32, &pdom_sched_type,
+ option_parser_register(opp, "-gpgpu_pdom_sched_type", OPT_INT32, &m_pdom_sched_type,
"0 = first ready warp found, 1 = random, 8 = loose round robin",
"8");
- option_parser_register(opp, "-gpgpu_spread_blocks_across_cores", OPT_BOOL,
- &gpgpu_spread_blocks_across_cores,
- "Spread block-issuing across all cores instead of filling up core by core (do NOT disable)",
- "1");
-
option_parser_register(opp, "-gpgpu_stall_on_use", OPT_BOOL,
- &gpgpu_stall_on_use,
+ &m_shader_config->gpgpu_stall_on_use,
"Enable stall-on-use",
"1");
- option_parser_register(opp, "-gpgpu_cuda_sim", OPT_BOOL, &gpgpu_cuda_sim,
- "use PTX instruction set",
- "1");
option_parser_register(opp, "-gpgpu_ptx_instruction_classification", OPT_INT32,
&gpgpu_ptx_instruction_classification,
"if enabled will classify ptx instruction types per kernel (Max 255 kernels now)",
@@ -502,34 +375,28 @@ void gpu_reg_options(option_parser_t opp)
"Clock Domain Frequencies in MhZ {<Core Clock>:<ICNT Clock>:<L2 Clock>:<DRAM Clock>}",
"500.0:2000.0:2000.0:2000.0");
- option_parser_register(opp, "-gpgpu_shmem_port_per_bank", OPT_INT32, &gpgpu_shmem_port_per_bank,
+ option_parser_register(opp, "-gpgpu_shmem_port_per_bank", OPT_INT32, &m_shader_config->gpgpu_shmem_port_per_bank,
"Number of access processed by a shared memory bank per cycle (default = 2)",
"2");
- option_parser_register(opp, "-gpgpu_cache_port_per_bank", OPT_INT32, &gpgpu_cache_port_per_bank,
+ option_parser_register(opp, "-gpgpu_cache_port_per_bank", OPT_INT32, &m_shader_config->gpgpu_cache_port_per_bank,
"Number of access processed by a cache bank per cycle (default = 2)",
"2");
- option_parser_register(opp, "-gpgpu_const_port_per_bank", OPT_INT32, &gpgpu_const_port_per_bank,
+ option_parser_register(opp, "-gpgpu_const_port_per_bank", OPT_INT32, &m_shader_config->gpgpu_const_port_per_bank,
"Number of access processed by a constant cache bank per cycle (default = 2)",
"2");
option_parser_register(opp, "-gpgpu_cflog_interval", OPT_INT32, &gpgpu_cflog_interval,
"Interval between each snapshot in control flow logger",
"0");
- option_parser_register(opp, "-gpgpu_partial_write_mask", OPT_INT32, &gpgpu_partial_write_mask,
- "use partial write mask to filter memory requests <1>No extra reads(use this!)<2>extra reads generated for partial chunks",
- "0");
option_parser_register(opp, "-gpu_concentration", OPT_INT32, &gpu_concentration,
"Number of shader cores per interconnection port (default = 1)",
"1");
- option_parser_register(opp, "-gpgpu_local_mem_map", OPT_INT32, &gpgpu_local_mem_map,
- "Mapping from local memory space address to simulated GPU physical address space (default = 1)",
+ option_parser_register(opp, "-gpgpu_local_mem_map", OPT_BOOL, &m_shader_config->gpgpu_local_mem_map,
+ "Mapping from local memory space address to simulated GPU physical address space (default = enabled)",
"1");
- option_parser_register(opp, "-gpgpu_reg_bank_conflict_model", OPT_BOOL, &gpgpu_reg_bank_conflict_model,
- "Turn on register bank conflict model (default = off)",
- "0");
- option_parser_register(opp, "-gpgpu_num_reg_banks", OPT_INT32, &gpgpu_num_reg_banks,
+ option_parser_register(opp, "-gpgpu_num_reg_banks", OPT_INT32, &m_shader_config->gpgpu_num_reg_banks,
"Number of register banks (default = 8)",
"8");
- option_parser_register(opp, "-gpgpu_reg_bank_use_warp_id", OPT_BOOL, &gpgpu_reg_bank_use_warp_id,
+ option_parser_register(opp, "-gpgpu_reg_bank_use_warp_id", OPT_BOOL, &m_shader_config->gpgpu_reg_bank_use_warp_id,
"Use warp ID in mapping registers to banks (default = off)",
"0");
option_parser_register(opp, "-gpgpu_ptx_inst_debug_to_file", OPT_BOOL,
@@ -542,135 +409,221 @@ void gpu_reg_options(option_parser_t opp)
option_parser_register(opp, "-gpgpu_ptx_inst_debug_thread_uid", OPT_INT32, &g_ptx_inst_debug_thread_uid,
"Thread UID for executed instructions' debug output",
"1");
- option_parser_register(opp, "-gpgpu_operand_collector", OPT_BOOL, &gpgpu_operand_collector,
+ option_parser_register(opp, "-gpgpu_ptx_convert_to_ptxplus", OPT_BOOL,
+ &g_ptx_convert_to_ptxplus,
+ "Convert embedded ptx to ptxplus",
+ "0");
+ option_parser_register(opp, "-gpgpu_ptx_save_converted_ptxplus", OPT_BOOL,
+ &g_ptx_save_converted_ptxplus,
+ "Saved converted ptxplus to a file",
+ "0");
+ option_parser_register(opp, "-gpgpu_operand_collector", OPT_BOOL, &m_shader_config->gpgpu_operand_collector,
"Enable operand collector model (default = off)",
"0");
- option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &gpgpu_operand_collector_num_units,
+ option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units,
"number of collecture units (default = 4)",
"4");
- option_parser_register(opp, "-gpgpu_operand_collector_num_units_sfu", OPT_INT32, &gpgpu_operand_collector_num_units_sfu,
+ option_parser_register(opp, "-gpgpu_operand_collector_num_units_sfu", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units_sfu,
"number of collecture units (default = 4)",
"4");
- option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &gpgpu_coalesce_arch,
+ option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &m_shader_config->gpgpu_coalesce_arch,
"Coalescing arch (default = 13, anything else is off for now)",
"13");
addrdec_setoption(opp);
L2c_options(opp);
visualizer_options(opp);
ptx_file_line_stats_options(opp);
+
+ m_options_set = true;
}
/////////////////////////////////////////////////////////////////////////////
-inline int mem2device(int memid) {
+int mem2device(int memid)
+{
return memid + gpu_n_tpc;
}
/////////////////////////////////////////////////////////////////////////////
+void increment_x_then_y_then_z( dim3 &i, const dim3 &bound)
+{
+ i.x++;
+ if ( i.x >= bound.x ) {
+ i.x = 0;
+ i.y++;
+ if ( i.y >= bound.y ) {
+ i.y = 0;
+ if( i.z < bound.z )
+ i.z++;
+ }
+ }
+}
+
+
+void gpgpu_sim::launch( kernel_info_t &kinfo )
+{
+ unsigned cta_size = kinfo.threads_per_cta();
+ if ( cta_size > m_shader_config->n_thread_per_shader ) {
+ printf("Execution error: Shader kernel CTA (block) size is too large for microarch config.\n");
+ printf(" CTA size (x*y*z) = %u, max supported = %u\n", cta_size,
+ m_shader_config->n_thread_per_shader );
+ printf(" => either change -gpgpu_shader argument in gpgpusim.config file or\n");
+ printf(" modify the CUDA source to decrease the kernel block size.\n");
+ abort();
+ }
+
+ m_running_kernels.push_back(kinfo);
+}
-/* Allocate memory for uArch structures */
-void init_gpu ()
+void gpgpu_sim::next_grid( unsigned &grid_num, class function_info *&entry )
+{
+ grid_num = ++m_grid_num;
+ m_the_kernel = m_running_kernels.front();
+ m_running_kernels.pop_front();
+ entry = m_the_kernel.entry();
+}
+
+gpgpu_sim::gpgpu_sim()
{
- // initialize the GPU microarchitecture model
- int i;
+ m_options_set=false;
+ m_grid_num=0;
+ m_shader_config = (shader_core_config*)calloc(1,sizeof(shader_core_config));
+ m_shader_stats = (shader_core_stats*)calloc(1,sizeof(shader_core_stats));
+ m_memory_config = (memory_config*)calloc(1,sizeof(memory_config));
+ m_memory_stats = NULL;
+}
+void set_ptx_warp_size(unsigned warp_size);
+
+void gpgpu_sim::init_gpu()
+{
+ assert( m_options_set );
+
gpu_max_cycle = gpu_max_cycle_opt;
- gpu_max_insn = gpu_max_insn_opt;
+ gpu_max_insn = gpu_max_insn_opt;
- i = sscanf(gpgpu_shader_core_pipeline_opt,"%d:%d:%d",
- &gpu_n_thread_per_shader, &warp_size, &pipe_simd_width);
- gpu_n_warp_per_shader = gpu_n_thread_per_shader / warp_size;
- num_warps_issuable = (int*) calloc(gpu_n_warp_per_shader+1, sizeof(int));
- num_warps_issuable_pershader = (int*) calloc(gpu_n_shader, sizeof(int));
- if (i == 2) {
- pipe_simd_width = warp_size;
- } else if (i == 3) {
- assert(warp_size % pipe_simd_width == 0);
+ int ntok = sscanf(gpgpu_shader_core_pipeline_opt,"%d:%d",
+ &m_shader_config->n_thread_per_shader,
+ &m_shader_config->warp_size);
+ set_ptx_warp_size(m_shader_config->warp_size);
+
+ m_shader_config->max_warps_per_shader = m_shader_config->n_thread_per_shader/m_shader_config->warp_size;
+ assert( !(m_shader_config->n_thread_per_shader % m_shader_config->warp_size) );
+
+ m_shader_stats->num_warps_issuable = (int*) calloc(m_shader_config->max_warps_per_shader+1, sizeof(int));
+ m_shader_stats->num_warps_issuable_pershader = (int*) calloc(m_n_shader, sizeof(int));
+ m_shader_stats->shader_cycle_distro = (unsigned int*) calloc(m_shader_config->warp_size + 3, sizeof(unsigned int));
+
+ if(ntok != 2) {
+ printf("GPGPU-Sim uArch: error while parsing configuration string gpgpu_shader_core_pipeline_opt\n");
+ abort();
}
- sscanf(gpgpu_runtime_stat, "%d:%x",
- &gpu_stat_sample_freq, &gpu_runtime_stat_flag);
+ sscanf(gpgpu_runtime_stat, "%d:%x", &gpu_stat_sample_freq, &gpu_runtime_stat_flag);
+
+ m_shader_config->pdom_sched_type = m_pdom_sched_type;
+ m_shader_config->gpgpu_n_shmem_bank=16;
- sc = (shader_core_ctx_t**) calloc(gpu_n_shader, sizeof(shader_core_ctx_t*));
- int mshr_que = gpu_n_mshr_per_thread;
- for (i=0;(unsigned)i<gpu_n_shader;i++) {
- sc[i] = shader_create("sh", i, /* shader id*/
- gpu_n_thread_per_shader, /* number of threads */
- mshr_que, /* number of MSHR per threads */
- fq_push, fq_has_buffer, gpgpu_simd_model);
+ m_sc = (shader_core_ctx**) calloc(m_n_shader, sizeof(shader_core_ctx*));
+ for (unsigned i=0;i<m_n_shader;i++) {
+ m_sc[i] = (shader_core_ctx*)calloc(sizeof(shader_core_ctx),1);
+ m_sc[i] = new (m_sc[i]) shader_core_ctx(this,"sh",i,i/gpu_concentration,m_shader_config,m_shader_stats);
}
- ptx_file_line_stats_create_exposed_latency_tracker(gpu_n_shader);
+ 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(gpu_n_shader, dwf_lut_size, dwf_lut_assoc,
- warp_size, pipe_simd_width,
- gpu_n_thread_per_shader, insn_size,
+ 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 );
- gpgpu_no_divg_load = gpgpu_no_divg_load && (gpgpu_simd_model == DWF);
- // always use no diverge on load for PDOM and NAIVE
- gpgpu_no_divg_load = gpgpu_no_divg_load || (gpgpu_simd_model == POST_DOMINATOR || gpgpu_simd_model == NO_RECONVERGE);
- if (gpgpu_no_divg_load) {
- //init_warp_tracker();
- printf("warp_tracker_pool size = %d\n", get_warp_tracker_pool().size());
- }
+ // 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);
- assert(gpu_n_shader % gpu_concentration == 0);
- gpu_n_tpc = gpu_n_shader / gpu_concentration;
+ m_shader_config->gpgpu_dwf_rr_stage_n_reg_banks=8;
- dram = (dram_t**) calloc(gpu_n_mem, sizeof(dram_t*));
- // L2request = (mem_fetch_t**) calloc(gpu_n_mem, sizeof(mem_fetch_t*));
- addrdec_setnchip(gpu_n_mem);
- unsigned int nbk,tCCD,tRRD,tRCD,tRAS,tRP,tRC,CL,WL,tWTR;
- sscanf(gpgpu_dram_timing_opt,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",&nbk,&tCCD,&tRRD,&tRCD,&tRAS,&tRP,&tRC,&CL,&WL,&tWTR);
- gpu_mem_n_bk = nbk;
- for (i=0;(unsigned)i<gpu_n_mem;i++) {
- dram[i] = dram_create(i, nbk, tCCD, tRRD, tRCD, tRAS, tRP, tRC,
- CL, WL, gpgpu_dram_burst_length/*BL*/, tWTR, gpgpu_dram_buswidth/*busW*/,
- gpgpu_dram_sched_queue_size, gpgpu_dram_scheduler);
- if (gpgpu_cache_dl2_opt)
- L2c_create(dram[i], gpgpu_cache_dl2_opt);
- }
- dram_log(CREATELOG);
- if (gpgpu_cache_dl2_opt && 1) {
- L2c_log(CREATELOG);
- }
- concurrent_row_access = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- num_activates = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- row_access = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- max_conc_access2samerow = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- max_servicetime2samerow = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
+ assert(m_n_shader % gpu_concentration == 0);
+ gpu_n_tpc = m_n_shader / gpu_concentration;
+
+ addrdec_setnchip(m_n_mem);
+ m_memory_partition_unit = new memory_partition_unit*[m_n_mem];
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i] = new memory_partition_unit(i, m_memory_config);
+ m_memory_stats = new memory_stats_t(m_n_mem,m_n_shader,m_shader_config,m_memory_config);
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->set_stats(m_memory_stats);
- for (i=0;(unsigned)i<gpu_n_mem ;i++ ) {
- concurrent_row_access[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- row_access[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- num_activates[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- max_conc_access2samerow[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- max_servicetime2samerow[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
+ concurrent_row_access = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*));
+ num_activates = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*));
+ row_access = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*));
+ max_conc_access2samerow = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*));
+ max_servicetime2samerow = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*));
+
+ for (unsigned i=0;i<m_n_mem ;i++ ) {
+ concurrent_row_access[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int));
+ row_access[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int));
+ num_activates[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int));
+ max_conc_access2samerow[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int));
+ max_servicetime2samerow[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int));
}
- memlatstat_init();
+ m_memory_stats = new memory_stats_t(m_n_mem,m_n_shader,m_shader_config,m_memory_config);
- L2c_init_stat();
- max_return_queue_length = (unsigned int*) calloc(gpu_n_shader, sizeof(unsigned int));
- icnt_init(gpu_n_tpc, gpu_n_mem);
+ m_shader_stats->max_return_queue_length = (unsigned int*) calloc(m_n_shader, sizeof(unsigned int));
- common_clock = 0;
+ icnt_init(gpu_n_tpc, m_n_mem,m_shader_config);
time_vector_create(NUM_MEM_REQ_STAT,MR_2SH_ICNT_INJECTED);
+ fprintf(stdout, "GPU performance model initialization complete.\n");
+ init_clock_domains();
+}
+
+int gpgpu_sim::shared_mem_size() const
+{
+ return m_shader_config->gpgpu_shmem_size;
+}
+
+int gpgpu_sim::num_registers_per_core() const
+{
+ return m_shader_config->gpgpu_shader_registers;
}
+int gpgpu_sim::wrp_size() const
+{
+ return m_shader_config->warp_size;
+}
+int gpgpu_sim::shader_clock() const
+{
+ return core_freq/1000;
+}
-void gpu_print_stat();
+void gpgpu_sim::set_prop( cudaDeviceProp *prop )
+{
+ m_cuda_properties = prop;
+}
-void init_clock_domains(void ) {
+const struct cudaDeviceProp *gpgpu_sim::get_prop() const
+{
+ return m_cuda_properties;
+}
+
+enum divergence_support_t gpgpu_sim::simd_model() const
+{
+ return m_shader_config->model;
+}
+
+void gpgpu_sim::init_clock_domains(void )
+{
sscanf(gpgpu_clock_domains,"%lf:%lf:%lf:%lf",
&core_freq, &icnt_freq, &l2_freq, &dram_freq);
core_freq = core_freq MhZ;
@@ -689,22 +642,21 @@ void init_clock_domains(void ) {
printf("GPGPU-Sim uArch: clock periods: %.20lf:%.20lf:%.20lf:%.20lf\n",core_period,icnt_period,l2_period,dram_period);
}
-void reinit_clock_domains(void)
+void gpgpu_sim::reinit_clock_domains(void)
{
- core_time = 0 ;
- dram_time = 0 ;
+ core_time = 0;
+ dram_time = 0;
icnt_time = 0;
l2_time = 0;
}
-void init_once(void ) {
- init_clock_domains();
-}
-
// return the number of cycle required to run all the trace on the gpu
-unsigned int run_gpu_sim(int grid_num)
+unsigned int gpgpu_sim::run_gpu_sim()
{
// run a CUDA grid on the GPU microarchitecture simulator
+ int grid_num = m_grid_num;
+ kernel_info_t &entry = m_the_kernel;
+ size_t program_size = get_kernel_code_size(entry.entry());
int not_completed;
int mem_busy;
@@ -717,28 +669,17 @@ unsigned int run_gpu_sim(int grid_num)
g_next_mf_request_uid = 1;
more_thread = 1;
gpu_sim_insn = 0;
- gpu_sim_insn_no_ld_const = 0;
+ m_shader_stats->gpu_sim_insn_no_ld_const = 0;
+ m_shader_stats->gpu_completed_thread = 0;
- gpu_completed_thread = 0;
-
- g_nthreads_issued = 0;
-
- static int one_time_inits_done = 0 ;
- if (!one_time_inits_done ) {
- init_once();
- }
reinit_clock_domains();
- assert(gpgpu_spread_blocks_across_cores); // this seems to be required, so let's make it explicit
- set_option_gpgpu_spread_blocks_across_cores(gpgpu_spread_blocks_across_cores);
- set_param_gpgpu_num_shaders(gpu_n_shader);
- for (unsigned i=0;i<gpu_n_shader;i++) {
- sc[i]->not_completed = 0;
- shader_reinit(sc[i],0,sc[i]->n_threads);
- }
+ set_param_gpgpu_num_shaders(m_n_shader);
+ for (unsigned i=0;i<m_n_shader;i++)
+ m_sc[i]->reinit(0,m_shader_config->n_thread_per_shader,true);
if (gpu_max_cta_opt != 0) {
g_total_cta_left = gpu_max_cta_opt;
} else {
- g_total_cta_left = ptx_sim_grid_size();
+ g_total_cta_left = m_the_kernel.num_blocks();
}
if (gpu_max_cta_opt != 0) {
// the maximum number of CTA has been reached, stop any further simulation
@@ -756,75 +697,57 @@ unsigned int run_gpu_sim(int grid_num)
// refind the diverge/reconvergence pairs
dwf_reset_reconv_pt();
- find_reconvergence_points();
-
- dwf_process_reconv_pts();
- dwf_reinit_schedulers(gpu_n_shader);
+ dwf_process_reconv_pts(entry.entry());
+ dwf_reinit_schedulers(m_n_shader);
// initialize the control-flow, memory access, memory latency logger
- create_thread_CFlogger( gpu_n_shader, gpu_n_thread_per_shader, ptx_kernel_program_size(), 0, gpgpu_cflog_interval );
- shader_CTA_count_create( gpu_n_shader, gpgpu_cflog_interval);
+ 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);
if (gpgpu_cflog_interval != 0) {
- insn_warp_occ_create( gpu_n_shader, warp_size, ptx_kernel_program_size() );
- shader_warp_occ_create( gpu_n_shader, warp_size, gpgpu_cflog_interval);
- shader_mem_acc_create( gpu_n_shader, gpu_n_mem, 4, gpgpu_cflog_interval);
- shader_mem_lat_create( gpu_n_shader, gpgpu_cflog_interval);
- shader_cache_access_create( gpu_n_shader, 3, gpgpu_cflog_interval);
+ insn_warp_occ_create( m_n_shader, m_shader_config->warp_size, program_size );
+ shader_warp_occ_create( m_n_shader, m_shader_config->warp_size, gpgpu_cflog_interval);
+ shader_mem_acc_create( m_n_shader, m_n_mem, 4, gpgpu_cflog_interval);
+ shader_mem_lat_create( m_n_shader, gpgpu_cflog_interval);
+ shader_cache_access_create( m_n_shader, 3, gpgpu_cflog_interval);
set_spill_interval (gpgpu_cflog_interval * 40);
}
// calcaulte the max cta count and cta size for local memory address mapping
- gpu_max_cta_per_shader = max_cta_per_shader(sc[0]);
+ m_shader_config->gpu_max_cta_per_shader = m_sc[0]->max_cta(entry.entry());
//gpu_max_cta_per_shader is limited by number of CTAs if not enough
- if (ptx_sim_grid_size() < gpu_max_cta_per_shader*gpu_n_shader) {
- gpu_max_cta_per_shader = (ptx_sim_grid_size() / gpu_n_shader);
- if (ptx_sim_grid_size() % gpu_n_shader)
- gpu_max_cta_per_shader++;
+ if (m_the_kernel.num_blocks() < m_shader_config->gpu_max_cta_per_shader*m_n_shader) {
+ m_shader_config->gpu_max_cta_per_shader = (m_the_kernel.num_blocks() / m_n_shader);
+ if (m_the_kernel.num_blocks() % m_n_shader)
+ m_shader_config->gpu_max_cta_per_shader++;
}
- unsigned int gpu_cta_size = ptx_sim_cta_size();
- gpu_padded_cta_size = (gpu_cta_size%32) ? 32*((gpu_cta_size/32)+1) : gpu_cta_size;
+ unsigned int gpu_cta_size = m_the_kernel.threads_per_cta();
+ m_shader_config->gpu_padded_cta_size = (gpu_cta_size%32) ? 32*((gpu_cta_size/32)+1) : gpu_cta_size;
if (g_network_mode) {
icnt_init_grid();
}
- // Initialize dram delay queues
- dram_delay_queues.resize(gpu_n_mem);
-
-
last_gpu_sim_insn = 0;
- // add this condition as well? (gpgpu_n_processed_writes < gpgpu_n_sent_writes)
while (not_completed || mem_busy || icnt2mem_busy) {
- gpu_sim_loop(grid_num);
-
+ gpu_sim_loop();
not_completed = 0;
- for (unsigned i=0;i<gpu_n_shader;i++) {
- not_completed += sc[i]->not_completed;
- }
- // dram_busy just check the request queue length into the dram
- // to make sure all the memory requests (esp the writes) are done
+ for (unsigned i=0;i<m_n_shader;i++)
+ not_completed += m_sc[i]->get_not_completed();
mem_busy = 0;
- for (unsigned i=0;i<gpu_n_mem;i++) {
- mem_busy += dram_busy(dram[i]);
- }
- // icnt to the memory should clean of any pending tranfers as well
- icnt2mem_busy = icnt_busy( );
-
- if (gpu_max_cycle && (gpu_tot_sim_cycle + gpu_sim_cycle) >= gpu_max_cycle) {
+ for (unsigned i=0;i<m_n_mem;i++)
+ mem_busy += m_memory_partition_unit[i]->busy();
+ icnt2mem_busy = icnt_busy();
+ if (gpu_max_cycle && (gpu_tot_sim_cycle + gpu_sim_cycle) >= gpu_max_cycle)
break;
- }
- if (gpu_max_insn && (gpu_tot_sim_insn + gpu_sim_insn) >= gpu_max_insn) {
+ if (gpu_max_insn && (gpu_tot_sim_insn + gpu_sim_insn) >= gpu_max_insn)
break;
- }
- if (gpu_deadlock_detect && gpu_deadlock) {
+ if (gpu_deadlock_detect && gpu_deadlock)
break;
- }
-
}
- memlatstat_lat_pw();
+ m_memory_stats->memlatstat_lat_pw(m_n_shader,m_shader_config->n_thread_per_shader,m_shader_config->warp_size);
gpu_tot_sim_cycle += gpu_sim_cycle;
gpu_tot_sim_insn += gpu_sim_insn;
- gpu_tot_completed_thread += gpu_completed_thread;
+ gpu_tot_completed_thread += m_shader_stats->gpu_completed_thread;
ptx_file_line_stats_write_file();
@@ -836,37 +759,60 @@ unsigned int run_gpu_sim(int grid_num)
icnt_overal_stat();
printf("----------------------------END-of-Interconnect-DETAILS-------------------------" );
}
- if (gpgpu_memlatency_stat & GPU_MEMLATSTAT_QUEUELOGS ) {
- dramqueue_latency_log_dump();
- dram_log(DUMPLOG);
- if (gpgpu_cache_dl2_opt) {
- L2c_log(DUMPLOG);
+ if (m_memory_config->gpgpu_memlatency_stat & GPU_MEMLATSTAT_QUEUELOGS ) {
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->queue_latency_log_dump(stdout);
+ if (m_memory_config->gpgpu_cache_dl2_opt) {
+ for(unsigned i=0; i<m_n_mem; i++)
+ m_memory_partition_unit[i]->L2c_log(DUMPLOG);
L2c_latency_log_dump();
}
}
-#define DEADLOCK 0
if (gpu_deadlock_detect && gpu_deadlock) {
fflush(stdout);
printf("GPGPU-Sim uArch: ERROR ** deadlock detected: last writeback @ gpu_sim_cycle %u (+ gpu_tot_sim_cycle %u) (%u cycles ago)\n",
(unsigned) gpu_sim_insn_last_update, (unsigned) (gpu_tot_sim_cycle-gpu_sim_cycle),
(unsigned) (gpu_sim_cycle - gpu_sim_insn_last_update ));
+ unsigned num_cores=0;
+ for (unsigned i=0;i<m_n_shader;i++) {
+ unsigned not_completed = m_sc[i]->get_not_completed();
+ if( not_completed ) {
+ if ( !num_cores ) {
+ printf("GPGPU-Sim uArch: DEADLOCK shader cores no longer committing instructions [core(# threads)]:\n" );
+ printf("GPGPU-Sim uArch: DEADLOCK %u(%u)", i, not_completed);
+ } else if (num_cores < 8 ) {
+ printf(" %u(%u)", i, not_completed);
+ } else if (num_cores == 8 ) {
+ printf(" + others ... ");
+ }
+ num_cores++;
+ }
+ }
+ printf("\n");
+ for (unsigned i=0;i<m_n_mem;i++) {
+ mem_busy += m_memory_partition_unit[i]->busy();
+ if( mem_busy )
+ printf("GPGPU-Sim uArch DEADLOCK: memory partition %u still busy\n", i);
+ }
+ if( icnt_busy() )
+ printf("GPGPU-Sim uArch DEADLOCK: iterconnect contains traffic\n");
+ printf("\nRe-run the simulator in gdb and use debug routines in .gdbinit to debug this\n");
fflush(stdout);
- assert(DEADLOCK);
+ abort();
}
return gpu_sim_cycle;
}
-void gpu_print_stat()
+void gpgpu_sim::gpu_print_stat() const
{
unsigned i;
- int j,k;
printf("gpu_sim_cycle = %lld\n", gpu_sim_cycle);
printf("gpu_sim_insn = %lld\n", gpu_sim_insn);
- printf("gpu_sim_no_ld_const_insn = %lld\n", gpu_sim_insn_no_ld_const);
+ printf("gpu_sim_no_ld_const_insn = %lld\n", m_shader_stats->gpu_sim_insn_no_ld_const);
printf("gpu_ipc = %12.4f\n", (float)gpu_sim_insn / gpu_sim_cycle);
- printf("gpu_completed_thread = %lld\n", gpu_completed_thread);
+ printf("gpu_completed_thread = %lld\n", m_shader_stats->gpu_completed_thread);
printf("gpu_tot_sim_cycle = %lld\n", gpu_tot_sim_cycle);
printf("gpu_tot_sim_insn = %lld\n", gpu_tot_sim_insn);
printf("gpu_tot_ipc = %12.4f\n", (float)gpu_tot_sim_insn / gpu_tot_sim_cycle);
@@ -876,32 +822,29 @@ void gpu_print_stat()
printf("gpgpu_n_processed_writes = %d\n", gpgpu_n_processed_writes);
// performance counter for stalls due to congestion.
- printf("gpu_stall_by_MSHRwb= %d\n", gpu_stall_by_MSHRwb);
- printf("gpu_stall_shd_mem = %d\n", gpu_stall_shd_mem );
+ printf("gpu_stall_by_MSHRwb= %d\n", m_shader_stats->gpu_stall_by_MSHRwb);
+ printf("gpu_stall_shd_mem = %d\n", m_shader_stats->gpu_stall_shd_mem );
printf("gpu_stall_wr_back = %d\n", gpu_stall_wr_back );
printf("gpu_stall_dramfull = %d\n", gpu_stall_dramfull);
printf("gpu_stall_icnt2sh = %d\n", gpu_stall_icnt2sh );
- printf("gpu_stall_sh2icnt = %d\n", gpu_stall_sh2icnt );
+ printf("gpu_stall_sh2icnt = %d\n", m_shader_stats->gpu_stall_sh2icnt );
// performance counter that are not local to one shader
shader_print_accstats(stdout);
- memlatstat_print();
+ m_memory_stats->memlatstat_print(m_n_mem,m_memory_config->gpu_mem_n_bk);
printf("max return queue length = ");
- for (unsigned i=0;i<gpu_n_shader;i++) {
- printf("%d ", max_return_queue_length[i]);
+ for (unsigned i=0;i<m_n_shader;i++) {
+ printf("%d ", m_shader_stats->max_return_queue_length[i]);
}
printf("\n");
// merge misses
- printf("L1 read misses = %d\n", L1_read_miss);
- printf("L1 write misses = %d\n", L1_write_miss);
- printf("L1 write hit on misses = %d\n", L1_write_hit_on_miss);
- printf("L1 writebacks = %d\n", L1_writeback);
- printf("L1 texture misses = %d\n", L1_texture_miss);
- printf("L1 const misses = %d\n", L1_const_miss);
- printf("L2_write_miss = %d\n", L2_write_miss);
- printf("L2_write_hit = %d\n", L2_write_hit);
- printf("L2_read_miss = %d\n", L2_read_miss);
- printf("L2_read_hit = %d\n", L2_read_hit);
+ printf("L1 read misses = %d\n", m_shader_stats->L1_read_miss);
+ printf("L1 write misses = %d\n", m_shader_stats->L1_write_miss);
+ printf("L1 write hit on misses = %d\n", m_shader_stats->L1_write_hit_on_miss);
+ printf("L1 writebacks = %d\n", m_shader_stats->L1_writeback);
+ printf("L1 texture misses = %d\n", m_shader_stats->L1_texture_miss);
+ printf("L1 const misses = %d\n", m_shader_stats->L1_const_miss);
+ m_memory_stats->print(stdout);
printf("made_read_mfs = %d\n", made_read_mfs);
printf("made_write_mfs = %d\n", made_write_mfs);
printf("freed_read_mfs = %d\n", freed_read_mfs);
@@ -909,66 +852,51 @@ void gpu_print_stat()
printf("freed_L2write_mfs = %d\n", freed_L2write_mfs);
printf("freed_dummy_read_mfs = %d\n", freed_dummy_read_mfs);
- printf("gpgpu_n_mem_read_local = %d\n", gpgpu_n_mem_read_local);
- printf("gpgpu_n_mem_write_local = %d\n", gpgpu_n_mem_write_local);
- printf("gpgpu_n_mem_read_global = %d\n", gpgpu_n_mem_read_global);
- printf("gpgpu_n_mem_write_global = %d\n", gpgpu_n_mem_write_global);
- printf("gpgpu_n_mem_texture = %d\n", gpgpu_n_mem_texture);
- printf("gpgpu_n_mem_const = %d\n", gpgpu_n_mem_const);
+ printf("gpgpu_n_mem_read_local = %d\n", m_shader_stats->gpgpu_n_mem_read_local);
+ printf("gpgpu_n_mem_write_local = %d\n", m_shader_stats->gpgpu_n_mem_write_local);
+ printf("gpgpu_n_mem_read_global = %d\n", m_shader_stats->gpgpu_n_mem_read_global);
+ printf("gpgpu_n_mem_write_global = %d\n", m_shader_stats->gpgpu_n_mem_write_global);
+ printf("gpgpu_n_mem_texture = %d\n", m_shader_stats->gpgpu_n_mem_texture);
+ printf("gpgpu_n_mem_const = %d\n", m_shader_stats->gpgpu_n_mem_const);
printf("max_n_mshr_used = ");
- for (unsigned i=0; i< gpu_n_shader; i++) printf("%d ", get_max_mshr_used(sc[i]));
+ for (unsigned i=0; i< m_n_shader; i++) printf("%d ", m_sc[i]->get_max_mshr_used() );
printf("\n");
- if (gpgpu_cache_dl2_opt) {
- L2c_print_stat( );
+ if (m_memory_config->gpgpu_cache_dl2_opt) {
+ m_memory_stats->L2c_print_stat( m_n_mem );
}
- for (unsigned i=0;i<gpu_n_mem;i++) {
- dram_print(dram[i],stdout);
- }
-
- for (i=0, j=0, k=0;i<gpu_n_shader;i++) {
- shd_cache_print(sc[i]->L1cache,stdout);
- j+=sc[i]->L1cache->miss;
- k+=sc[i]->L1cache->access;
- }
- printf("L1 Data Cache Total Miss Rate = %0.3f\n", (float)j/k);
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->print(stdout);
- for (i=0,j=0,k=0;i<gpu_n_shader;i++) {
- shd_cache_print(sc[i]->L1texcache,stdout);
- j+=sc[i]->L1texcache->miss;
- k+=sc[i]->L1texcache->access;
- }
- printf("L1 Texture Cache Total Miss Rate = %0.3f\n", (float)j/k);
+ unsigned a,m;
+ for (unsigned i=0, a=0, m=0;i<m_n_shader;i++)
+ m_sc[i]->L1cache_print(stdout,a,m);
+ printf("L1 Data Cache Total Miss Rate = %0.3f\n", (float)m/a);
+ for (i=0,a=0,m=0;i<m_n_shader;i++)
+ m_sc[i]->L1texcache_print(stdout,a,m);
+ printf("L1 Texture Cache Total Miss Rate = %0.3f\n", (float)m/a);
+ for (i=0,a=0,m=0;i<m_n_shader;i++)
+ m_sc[i]->L1constcache_print(stdout,a,m);
+ printf("L1 Const Cache Total Miss Rate = %0.3f\n", (float)m/a);
- for (i=0,j=0,k=0;i<gpu_n_shader;i++) {
- shd_cache_print(sc[i]->L1constcache,stdout);
- j+=sc[i]->L1constcache->miss;
- k+=sc[i]->L1constcache->access;
- }
- printf("L1 Const Cache Total Miss Rate = %0.3f\n", (float)j/k);
-
- if (gpgpu_cache_dl2_opt) {
+ if (m_memory_config->gpgpu_cache_dl2_opt)
L2c_print_cache_stat();
- }
printf("n_regconflict_stall = %d\n", n_regconflict_stall);
- if (gpgpu_simd_model == DWF) {
+ if (m_shader_config->model == DWF) {
dwf_print_stat(stdout);
}
- if (gpgpu_simd_model == POST_DOMINATOR) {
+ if (m_shader_config->model == POST_DOMINATOR) {
printf("num_warps_issuable:");
- for (unsigned i=0;i<(gpu_n_warp_per_shader+1);i++) {
- printf("%d ", num_warps_issuable[i]);
+ for (unsigned i=0;i<(m_shader_config->max_warps_per_shader+1);i++) {
+ printf("%d ", m_shader_stats->num_warps_issuable[i]);
}
printf("\n");
}
- if (gpgpu_strict_simd_wrbk) {
- printf("warp_conflict_at_writeback = %d\n", warp_conflict_at_writeback);
- }
- printf("gpgpu_commit_pc_beyond_two = %d\n", gpgpu_commit_pc_beyond_two);
+ printf("gpgpu_commit_pc_beyond_two = %d\n", m_shader_stats->gpgpu_commit_pc_beyond_two);
print_shader_cycle_distro( stdout );
@@ -987,67 +915,111 @@ void gpu_print_stat()
fflush(stdout);
}
-////////////////////////////////////////////////////////////////////////////////////
-// Wrapper function for shader cores' memory system:
-////////////////////////////////////////////////////////////////////////////////////
-// a hack to make the size of a packet discrete multiples of the interconnect's flit_size.
-static inline
-unsigned int fill_to_next_flit(unsigned int size)
+// performance counter that are not local to one shader
+void gpgpu_sim::shader_print_accstats( FILE* fout ) const
{
- assert (g_network_mode == INTERSIM);
- return size;
-}
+ fprintf(fout, "gpgpu_n_load_insn = %d\n", m_shader_stats->gpgpu_n_load_insn);
+ fprintf(fout, "gpgpu_n_store_insn = %d\n", m_shader_stats->gpgpu_n_store_insn);
+ fprintf(fout, "gpgpu_n_shmem_insn = %d\n", m_shader_stats->gpgpu_n_shmem_insn);
+ fprintf(fout, "gpgpu_n_tex_insn = %d\n", m_shader_stats->gpgpu_n_tex_insn);
+ fprintf(fout, "gpgpu_n_const_mem_insn = %d\n", m_shader_stats->gpgpu_n_const_insn);
+ fprintf(fout, "gpgpu_n_param_mem_insn = %d\n", m_shader_stats->gpgpu_n_param_insn);
+ fprintf(fout, "gpgpu_n_shmem_bkconflict = %d\n", m_shader_stats->gpgpu_n_shmem_bkconflict);
+ fprintf(fout, "gpgpu_n_cache_bkconflict = %d\n", m_shader_stats->gpgpu_n_cache_bkconflict);
+ fprintf(fout, "gpgpu_n_intrawarp_mshr_merge = %d\n", m_shader_stats->gpgpu_n_intrawarp_mshr_merge);
+ fprintf(fout, "gpgpu_n_cmem_portconflict = %d\n", m_shader_stats->gpgpu_n_cmem_portconflict);
-unsigned char check_icnt_has_buffer(unsigned long long int *addr, int *bsize,
- int n_addr, int sid )
-{
- addrdec_t tlx;
- static unsigned int *req_buffer = NULL;
- //the req_buf size can be equal to gpu_n_mem ; gpu_n_shader is added to make it compatible
- //with the case where a mem controller is sending to shd
- if (!req_buffer) req_buffer = (unsigned int*)malloc((gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int));
- memset(req_buffer, 0, (gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int));
+ fprintf(fout, "gpgpu_n_partial_writes = %d\n", m_shader_stats->gpgpu_n_partial_writes);
- // aggregate all buffer requirement of all memory accesses by dram chips
- for (int i=0; i< n_addr; i++) {
- addrdec_tlx(addr[i],&tlx);
- req_buffer[tlx.chip] += fill_to_next_flit(bsize[i]);
- }
+ fprintf(fout, "gpgpu_stall_shd_mem[c_mem][bk_conf] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[C_MEM][BK_CONF]);
+ fprintf(fout, "gpgpu_stall_shd_mem[c_mem][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[C_MEM][MSHR_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[c_mem][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[C_MEM][ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[t_mem][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[T_MEM][MSHR_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[t_mem][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[T_MEM][ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[s_mem][bk_conf] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[S_MEM][BK_CONF]);
+ fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][bk_conf] = %d\n",
+ m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][BK_CONF] +
+ m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][BK_CONF] +
+ m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][BK_CONF] +
+ m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][BK_CONF]
+ ); // coalescing stall at data cache
+ fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][coal_stall] = %d\n",
+ m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][COAL_STALL] +
+ m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][COAL_STALL] +
+ m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][COAL_STALL] +
+ m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][COAL_STALL]
+ ); // coalescing stall + bank conflict at data cache
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][MSHR_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_CACHE_RSRV_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][MSHR_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_CACHE_RSRV_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][MSHR_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_CACHE_RSRV_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][MSHR_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_ICNT_RC_FAIL]);
+ fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_CACHE_RSRV_FAIL]);
- int tpc_id = sid / gpu_concentration;
+ fprintf(fout, "gpu_reg_bank_conflict_stalls = %d\n", m_shader_stats->gpu_reg_bank_conflict_stalls);
+}
- return icnt_has_buffer(tpc_id, req_buffer);
+unsigned gpgpu_sim::threads_per_core() const
+{
+ return m_shader_config->n_thread_per_shader;
}
-unsigned char single_check_icnt_has_buffer(int chip, int sid, unsigned char is_write )
+void gpgpu_sim::mem_instruction_stats(inst_t* warp)
{
- static unsigned int *req_buffer = NULL;
- //the req_buf size can be equal to gpu_n_mem ; gpu_n_shader is added to make it compatible
- //with the case where a mem controller is sending to shd
- if (!req_buffer) req_buffer = (unsigned int*)malloc((gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int));
- memset(req_buffer, 0, (gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int));
-
- // aggregate all buffer requirement of all memory accesses by dram chips
-
- int b_size;
- if (is_write)
- b_size = sc[sid]->L1cache->line_sz;
- else
- b_size = READ_PACKET_SIZE;
- req_buffer[chip] += fill_to_next_flit(b_size);
-
- int tpc_id = sid / gpu_concentration;
-
- return icnt_has_buffer(tpc_id, req_buffer);
+ 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){
+ m_shader_stats->gpgpu_n_store_insn++;
+ } else {
+ m_shader_stats->gpgpu_n_load_insn++;
+ }
+ break;
+ default:
+ abort();
+ }
+ }
}
-int max_n_addr = 0;
+////////////////////////////////////////////////////////////////////////////////////
+// Wrapper function for shader cores' memory system:
+////////////////////////////////////////////////////////////////////////////////////
// Check the memory system for buffer availability
-unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid )
+unsigned char gpgpu_sim::fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid )
{
//requests should be single always now
int rsize = bsize;
@@ -1055,76 +1027,36 @@ unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write,
if (!write) {
rsize = READ_PACKET_SIZE;
}
- return check_icnt_has_buffer(&addr, &rsize, 1, sid);
+ return check_icnt_has_buffer(addr, rsize, sid);
}
-// Takes in memory address and their parameters and pushes to the fetch queue
-unsigned char fq_push(unsigned long long int addr, int bsize, unsigned char write, partial_write_mask_t partial_write_mask,
- int sid, int wid, mshr_entry* mshr, int cache_hits_waiting,
- enum mem_access_type mem_acc, address_type pc)
+unsigned char gpgpu_sim::check_icnt_has_buffer(unsigned long long int addr, int bsize, int sid )
{
- mem_fetch_t *mf;
-
- mf = (mem_fetch_t*) calloc(1,sizeof(mem_fetch_t));
- mf->request_uid = g_next_mf_request_uid++;
- mf->addr = addr;
- mf->nbytes_L1 = bsize;
- mf->sid = sid;
- mf->source_node = sid / gpu_concentration;
- mf->wid = wid;
- mf->cache_hits_waiting = cache_hits_waiting;
- mf->txbytes_L1 = 0;
- mf->rxbytes_L1 = 0;
- mf->mshr = mshr;
- if (mshr) mshr->mf = (void*)mf; // for debugging
- mf->write = write;
+ int tpc_id = sid / gpu_concentration;
+ return icnt_has_buffer(tpc_id, bsize);
+}
- if (write)
- made_write_mfs++;
- else
- made_read_mfs++;
- memlatstat_start(mf);
- addrdec_tlx(addr,&mf->tlx);
- mf->bank = mf->tlx.bk;
- mf->chip = mf->tlx.chip;
- if (gpgpu_cache_dl2_opt)
- mf->nbytes_L2 = L2c_get_linesize( dram[mf->tlx.chip] );
+unsigned gpgpu_sim::get_L2_linesize() const
+{
+ if (m_memory_partition_unit[0]->has_cache())
+ return m_memory_partition_unit[0]->L2c_get_linesize();
else
- mf->nbytes_L2 = 0;
- mf->txbytes_L2 = 0;
- mf->rxbytes_L2 = 0;
-
- mf->write_mask = partial_write_mask;
- if (!write) assert(partial_write_mask == NO_PARTIAL_WRITE);
-
- // stat collection codes
- mf->mem_acc = mem_acc;
- mf->pc = pc;
-
- switch (mem_acc) {
- case CONST_ACC_R: gpgpu_n_mem_const++; break;
- case TEXTURE_ACC_R: gpgpu_n_mem_texture++; break;
- case GLOBAL_ACC_R: gpgpu_n_mem_read_global++; break;
- case GLOBAL_ACC_W: gpgpu_n_mem_write_global++; break;
- case LOCAL_ACC_R: gpgpu_n_mem_read_local++; break;
- case LOCAL_ACC_W: gpgpu_n_mem_write_local++; break;
- default: assert(0);
- }
-
- return(issue_mf_from_fq(mf));
-
+ return 0;
}
-int issue_mf_from_fq(mem_fetch_t *mf){
+int gpgpu_sim::issue_mf_from_fq(mem_fetch *mf)
+{
+ m_memory_stats->memlatstat_start(mf);
int destination; // where is the next level of memory?
destination = mf->tlx.chip;
int tpc_id = mf->sid / gpu_concentration;
- if (mf->mshr) mshr_update_status(mf->mshr,IN_ICNT2MEM);
- if (!mf->write) {
+ if (mf->mshr) mf->mshr->set_status(IN_ICNT2MEM);
+ if (!mf->m_write) {
mf->type = RD_REQ;
assert( mf->timestamp == (gpu_sim_cycle+gpu_tot_sim_cycle) );
- time_vector_update(mf->mshr->insts[0].uid, MR_ICNT_PUSHED, gpu_sim_cycle+gpu_tot_sim_cycle, mf->type );
+ if( mf->mshr && mf->mshr->has_inst() )
+ time_vector_update(mf->mshr->get_insts_uid(), MR_ICNT_PUSHED, gpu_sim_cycle+gpu_tot_sim_cycle, mf->type );
icnt_push(tpc_id, mem2device(destination), (void*)mf, READ_PACKET_SIZE);
} else {
mf->type = WT_REQ;
@@ -1137,260 +1069,235 @@ int issue_mf_from_fq(mem_fetch_t *mf){
return 0;
}
-inline void fill_shd_L1_with_new_line(shader_core_ctx_t * sc, mem_fetch_t * mf) {
- unsigned long long int repl_addr = -1;
+void shader_core_ctx::fill_shd_L1_with_new_line(mem_fetch * mf)
+{
// When the data arrives, it flags all the appropriate MSHR
// entries accordingly (by checking the address in each entry )
- memlatstat_read_done(mf);
-
- mshr_return_from_mem(sc, mf->mshr);
-
- if (mf->mshr->istexture) {
- shd_cache_fill(sc->L1texcache,mf->addr,sc->gpu_cycle);
- repl_addr = -1;
- } else if (mf->mshr->isconst) {
- shd_cache_fill(sc->L1constcache,mf->addr,sc->gpu_cycle);
- repl_addr = -1;
+ if (mf->mshr->isinst()) {
+ shd_cache_fill(m_L1I,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle);
+ m_warp[mf->mshr->get_warp_id()].clear_imiss_pending();
+ delete mf->mshr;
+ mf->mshr=NULL;
} else {
- if (!gpgpu_no_dl1) {
- //if we are doing a writeback cache we may have marked off a mask in the mshr
- //only write into the cache unmasked bytes.
- //since this doesn't affect timing we don't actually do it.
- repl_addr = shd_cache_fill(sc->L1cache,mf->addr,sc->gpu_cycle);
- }
+ m_mshr_unit->mshr_return_from_mem(mf->mshr);
+ if (mf->mshr->istexture())
+ shd_cache_fill(m_L1T,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle);
+ else if (mf->mshr->isconst())
+ shd_cache_fill(m_L1C,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle);
+ else if (!m_config->gpgpu_no_dl1)
+ shd_cache_fill(m_L1D,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle);
}
-
freed_read_mfs++;
- free(mf);
+ delete mf;
}
-unsigned char fq_pop(int tpc_id)
+void shader_core_ctx::store_ack( class mem_fetch *mf )
{
- mem_fetch_t *mf;
-
- mf = (mem_fetch_t*) icnt_pop(tpc_id);
-
- // if there is a memory fetch request coming back, forward it to the proper shader core
- if (mf) {
- assert(mf->type == REPLY_DATA);
- time_vector_update(mf->mshr->insts[0].uid ,MR_2SH_FQ_POP,gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ) ;
- fill_shd_L1_with_new_line(sc[mf->sid], mf);
+ if (!strcmp("GT200",m_config->pipeline_model) ) {
+ unsigned warp_id = mf->wid;
+ m_warp[warp_id].dec_store_req();
}
- return 0;
}
-////////////////////////////////////////////////////////////////////////////////////////////////
-
-int issue_block2core( shader_core_ctx_t *shdr, int grid_num )
+void gpgpu_sim::fq_pop(int tpc_id)
{
- int tid, nthreads_2beissued, more_threads;
- int nthreads_in_block= 0;
- int start_thread = 0;
- int end_thread = shdr->n_threads;
- int cta_id=-1;
- int cta_size=0;
- int padded_cta_size;
+ mem_fetch *mf = (mem_fetch*) icnt_pop(tpc_id);
+ if (!mf)
+ return;
+ assert(mf->type == REPLY_DATA);
+ if( mf->mshr && mf->mshr->has_inst() )
+ time_vector_update(mf->mshr->get_insts_uid() ,MR_2SH_FQ_POP,gpu_sim_cycle+gpu_tot_sim_cycle, mf->type );
+ if (mf->m_write) {
+ m_sc[mf->sid]->store_ack(mf);
+ delete mf;
+ } else {
+ m_memory_stats->memlatstat_read_done(mf,m_shader_config->max_warps_per_shader);
+ m_sc[mf->sid]->fill_shd_L1_with_new_line(mf);
+ }
+}
- cta_size = ptx_sim_cta_size();
- padded_cta_size = cta_size;
+////////////////////////////////////////////////////////////////////////////////////////////////
- assert(gpgpu_spread_blocks_across_cores); //should be if muliple CTA per shader supported
+/**
+ * Launches a cooperative thread array (CTA).
+ *
+ * @param kernel
+ * object that tells us which kernel to ask for a CTA from
+ */
- for (unsigned i=0;i<max_cta_per_shader(shdr);i++ ) { //try to find next empty cta slot
- if (shdr->cta_status[i]==0) { //
- cta_id=i;
+void shader_core_ctx::issue_block2core( kernel_info_t &kernel )
+{
+ // find a free CTA context
+ unsigned free_cta_hw_id=(unsigned)-1;
+ unsigned max_concurrent_cta_this_kernel = max_cta(kernel.entry());
+ assert( max_concurrent_cta_this_kernel <= MAX_CTA_PER_SHADER );
+ for (unsigned i=0;i<max_concurrent_cta_this_kernel;i++ ) {
+ if( m_cta_status[i]==0 ) {
+ free_cta_hw_id=i;
break;
}
- }
- assert( cta_id!=-1);//must have found a CTA to run
- if (padded_cta_size%warp_size) {
- padded_cta_size = ((padded_cta_size/warp_size)+1)*(warp_size);
- }
- start_thread = cta_id * padded_cta_size;
- end_thread = start_thread + cta_size;
- shader_reinit(shdr,start_thread, end_thread);
-
- // issue threads in blocks (if it is specified)
- warp_set_t warps;
- for (int i = start_thread; i<end_thread; i++) { //setup the block
- unsigned warp_id = i/warp_size;
- shdr->thread[i].cta_id = cta_id;
- nthreads_in_block += ptx_sim_init_thread(&shdr->thread[i].ptx_thd_info,shdr->sid,i,cta_size-(i-start_thread),shdr->n_threads/*cta_size*/,shdr,cta_id,warp_id);
- warps.set( warp_id );
- }
- shdr->allocate_barrier( cta_id, warps );
+ }
+ assert( free_cta_hw_id!=(unsigned)-1 );
- shader_init_CTA(shdr, start_thread, end_thread);
- nthreads_2beissued = nthreads_in_block;
- shdr->cta_status[cta_id]+=nthreads_2beissued;
- assert( nthreads_2beissued ); //we should have not reached this point if there is no more thread to -
+ // determine hardware threads and warps that will be used for this CTA
+ int cta_size = kernel.threads_per_cta();
- assert( (unsigned) nthreads_2beissued <= shdr->n_threads); //confirm threads to be issued is less than or equal to number of threads supported by microarchitecture
+ // hw warp id = hw thread id mod warp size, so we need to find a range
+ // of hardware thread ids corresponding to an integral number of hardware
+ // thread ids
+ int padded_cta_size = cta_size;
+ if (cta_size%m_config->warp_size)
+ padded_cta_size = ((cta_size/m_config->warp_size)+1)*(m_config->warp_size);
+ unsigned start_thread = free_cta_hw_id * padded_cta_size;
+ unsigned end_thread = start_thread + cta_size;
- int n_cta_issued= nthreads_2beissued/cta_size ;//+ nthreads_2beissued%cta_size;
- shdr->n_active_cta += n_cta_issued;
- shader_CTA_count_log(shdr->sid, n_cta_issued);
- g_total_cta_left-= n_cta_issued;
+ // reset the microarchitecture state of the selected hardware thread and warp contexts
+ reinit(start_thread, end_thread,false);
+
+ // initalize scalar threads and determine which hardware warps they are allocated to
+ // bind functional simulation state of threads to hardware resources (simulation)
+ warp_set_t warps;
+ unsigned nthreads_in_block= 0;
+ for (unsigned i = start_thread; i<end_thread; i++) {
+ m_thread[i].m_cta_id = free_cta_hw_id;
+ unsigned warp_id = i/m_config->warp_size;
+ nthreads_in_block += ptx_sim_init_thread(kernel,&m_thread[i].m_functional_model_thread_state,m_sid,i,cta_size-(i-start_thread),m_config->n_thread_per_shader,this,free_cta_hw_id,warp_id);
+ warps.set( warp_id );
+ }
+ assert( nthreads_in_block > 0 && nthreads_in_block <= m_config->n_thread_per_shader); // should be at least one, but less than max
+ m_cta_status[free_cta_hw_id]=nthreads_in_block;
- more_threads = 1;
- if (gpgpu_spread_blocks_across_cores) {
- nthreads_2beissued += start_thread;
- }
- printf("GPGPU-Sim uArch: Shader %d initializing CTA #%d with hw tids from %d to %d @(%lld,%lld)",
- shdr->sid, cta_id, start_thread, nthreads_2beissued, gpu_sim_cycle, gpu_tot_sim_cycle );
- printf(" shdr->not_completed = %d\n", shdr->not_completed);
-
- for (tid=start_thread;tid<nthreads_2beissued;tid++) {
+ // now that we know which warps are used in this CTA, we can allocate
+ // resources for use in CTA-wide barrier operations
+ allocate_barrier( free_cta_hw_id, warps );
- // reset complete flag for stream
- shdr->not_completed += 1;
- assert( shdr->warp[tid/warp_size].n_completed > 0 );
- assert( shdr->warp[tid/warp_size].n_completed <= warp_size);
- shdr->warp[tid/warp_size].n_completed--;
+ // initialize the SIMT stacks and fetch hardware
+ init_warps(start_thread, end_thread);
- // set avail4fetch flag to ready
- shdr->thread[tid].avail4fetch = 1;
- assert( shdr->warp[tid/warp_size].n_avail4fetch < warp_size );
- shdr->warp[tid/warp_size].n_avail4fetch++;
-
- g_nthreads_issued++;
- }
+ m_n_active_cta++;
+ g_total_cta_left-=1; // used for exiting early from simulation
- if (!nthreads_in_block) more_threads = 0;
- return more_threads; //if there are no more threads to be issued, return 0
+ shader_CTA_count_log(m_sid, 1);
+
+ printf("GPGPU-Sim uArch: Shader %d initialized CTA #%d with hw tids from %d to %d @(%lld,%lld)",
+ m_sid, free_cta_hw_id, start_thread, start_thread+nthreads_in_block, gpu_sim_cycle, gpu_tot_sim_cycle );
+ printf(" active threads = %d\n", get_not_completed() );
+
}
+
///////////////////////////////////////////////////////////////////////////////////////////
// wrapper code to to create an illusion of a memory controller with L2 cache.
-//
-int mem_ctrl_full( int mc_id )
-{
- if (gpgpu_cache_dl2_opt) {
- return L2c_full( dram[mc_id] );
- } else {
- return( gpgpu_dram_sched_queue_size && dram_full(dram[mc_id]) );
- }
-}
//#define DEBUG_PARTIAL_WRITES
-void mem_ctrl_push( int mc_id, mem_fetch_t* mf )
+void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle )
{
- dram[mc_id]->m_request_tracker.insert(mf);
- if (gpgpu_cache_dl2_opt) {
- L2c_push(dram[mc_id], mf);
- } else {
- addrdec_t tlx;
- addrdec_tlx(mf->addr, &tlx);
-#if 0 //old chunking no longer valid.
- if (gpgpu_partial_write_mask && mf->write) {
- assert( gpgpu_no_dl1 ); // gpgpu_partial_write_mask is not supported with caches for now
- }
-#endif //#if 0 //old chunking no longer valid
- dram_push(dram[mc_id],
- tlx.bk, tlx.row, tlx.col,
- mf->nbytes_L1, mf->write,
- mf->wid, mf->sid, mf->cache_hits_waiting, mf->addr, mf);
- memlatstat_dram_access(mf, mc_id, tlx.bk);
- if (mf->mshr) mshr_update_status(mf->mshr,IN_DRAM_REQ_QUEUE);
- }
+ if (req) {
+ rop_delay_t r;
+ r.req = req;
+ r.ready_cycle = cycle + 115; // Add 115*4=460 delay cycles
+ m_rop.push(r);
+ }
+ if ( !m_rop.empty() && (cycle >= m_rop.front().ready_cycle) ) {
+ mem_fetch* mf = m_rop.front().req;
+ m_rop.pop();
+ if (mf->type==RD_REQ) {
+ if ( mf->mshr && mf->mshr->has_inst() )
+ time_vector_update(mf->mshr->get_insts_uid(),MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ;
+ } else {
+ if ( mf->mshr && !mf->mshr->isinst() )
+ time_vector_update(mf->request_uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ;
+ }
+ m_stats->memlatstat_icnt2mem_pop(mf);
+ request_tracker_insert(mf);
+ if (m_config->gpgpu_cache_dl2_opt) {
+ if (m_config->gpgpu_l2_readoverwrite && mf->m_write)
+ cbtoL2writequeue->push(mf,gpu_sim_cycle);
+ else
+ cbtoL2queue->push(mf,gpu_sim_cycle);
+ m_accessLocality->access(mf);
+ if (mf->mshr) mf->mshr->set_status(IN_CBTOL2QUEUE);
+ } else {
+ m_dram->push(mf);
+ if (mf->mshr) mf->mshr->set_status(IN_DRAM_REQ_QUEUE);
+ }
+ }
}
-void* mem_ctrl_pop( int mc_id )
+mem_fetch* memory_partition_unit::pop()
{
- mem_fetch_t* mf;
- if (gpgpu_cache_dl2_opt) {
- mf = L2c_pop(dram[mc_id]);
- if (mf && mf->mshr && mf->mshr->insts[0].callback.function) {
- dram_callback_t* cb = &(mf->mshr->insts[0].callback);
- cb->function(cb->instruction, cb->thread);
+ mem_fetch* mf;
+ if (m_config->gpgpu_cache_dl2_opt) {
+ mf = L2c_pop(m_dram);
+ if (mf && mf->mshr && mf->mshr->isatomic() ) {
+ dram_callback_t &cb = mf->mshr->get_atomic_callback();
+ cb.function(cb.instruction, cb.thread);
}
- dram[mc_id]->m_request_tracker.erase(mf);
- return mf;
} else {
- mf = static_cast<mem_fetch_t*> (dq_pop(dram[mc_id]->returnq)); //dram_pop(dram[mc_id]);
+ mf = m_dram->returnq_pop(gpu_sim_cycle);
if (mf) mf->type = REPLY_DATA;
- if (mf && mf->mshr && mf->mshr->insts[0].callback.function) {
- dram_callback_t* cb = &(mf->mshr->insts[0].callback);
- cb->function(cb->instruction, cb->thread);
+ if (mf && mf->mshr && mf->mshr->isatomic() ) {
+ dram_callback_t &cb = mf->mshr->get_atomic_callback();
+ cb.function(cb.instruction, cb.thread);
}
- dram[mc_id]->m_request_tracker.erase(mf);
- return mf;
}
+ request_tracker_erase(mf);
+ return mf;
}
-void* mem_ctrl_top( int mc_id )
+mem_fetch* memory_partition_unit::top()
{
- mem_fetch_t* mf;
- if (gpgpu_cache_dl2_opt) {
- return L2c_top(dram[mc_id]);
+ if (m_config->gpgpu_cache_dl2_opt) {
+ return L2tocbqueue->top();
} else {
- mf = static_cast<mem_fetch_t*> (dq_top(dram[mc_id]->returnq));//dram_top(dram[mc_id]);
+ mem_fetch* mf = m_dram->returnq_top();
if (mf) mf->type = REPLY_DATA;
- return mf ;//dram_top(dram[mc_id]);
+ return mf;
}
}
-void get_dram_output ( dram_t* dram_p )
-{
- mem_fetch_t* mf;
- mem_fetch_t* mf_top;
- mf_top = (mem_fetch_t*) dram_top(dram_p); //test
+void memory_partition_unit::issueCMD()
+{
+ mem_fetch* mf_top = m_dram->top();
if (mf_top) {
if (mf_top->type == DUMMY_READ) {
- dram_pop(dram_p);
+ m_dram->pop();
free(mf_top);
freed_dummy_read_mfs++;
return;
}
}
- if (gpgpu_cache_dl2_opt) {
- L2c_get_dram_output( dram_p );
+ if (m_config->gpgpu_cache_dl2_opt) {
+ L2c_get_dram_output();
} else {
- if ( dq_full(dram_p->returnq) ) return;
- mf = (mem_fetch_t*) dram_pop(dram_p);
+ if ( m_dram->returnq_full() )
+ return;
+ mem_fetch* mf = m_dram->pop();
assert (mf_top==mf );
if (mf) {
- dq_push(dram_p->returnq, mf);
- if (mf->mshr) mshr_update_status(mf->mshr,IN_DRAMRETURN_Q);
+ m_dram->returnq_push(mf,gpu_sim_cycle);
+ if (mf->mshr) mf->mshr->set_status(IN_DRAMRETURN_Q);
}
}
+ m_dram->issueCMD();
+ m_dram->dram_log(SAMPLELOG);
}
-void dram_log (int task ) {
- static void ** mrqq_Dist; //memory request queue inside DRAM
- if (task == CREATELOG) {
- mrqq_Dist = (void **) calloc(gpu_n_mem,sizeof(void*));
- for (unsigned i=0;i<gpu_n_mem;i++) {
- if (dram[i]->queue_limit)
- mrqq_Dist[i] = StatCreate("mrqq_length",1,dram[i]->queue_limit);
- else //queue length is unlimited;
- mrqq_Dist[i] = StatCreate("mrqq_length",1,64); //track up to 64 entries
- }
- } else if (task == SAMPLELOG) {
- for (unsigned i=0;i<gpu_n_mem;i++) {
- StatAddSample(mrqq_Dist[i], dram_que_length(dram[i]));
- }
- } else if (task == DUMPLOG) {
- for (unsigned i=0;i<gpu_n_mem;i++) {
- printf ("Queue Length DRAM[%d] ",i);StatDisp(mrqq_Dist[i]);
- }
- }
-}
-
-void dramqueue_latency_log_dump()
+void dram_t::dram_log( int task )
{
- for (unsigned i=0;i<gpu_n_mem;i++) {
- printf ("(LOGB2)Latency DRAM[%d] ",i);StatDisp(dram[i]->mrqq->lat_stat);
- printf ("(LOGB2)Latency DRAM[%d] ",i);StatDisp(dram[i]->rwq->lat_stat);
+ if (task == SAMPLELOG) {
+ StatAddSample(mrqq_Dist, que_length());
+ } else if (task == DUMPLOG) {
+ printf ("Queue Length DRAM[%d] ",id);StatDisp(mrqq_Dist);
}
}
//Find next clock domain and increment its time
-inline int next_clock_domain(void)
+int gpgpu_sim::next_clock_domain(void)
{
double smallest = min3(core_time,icnt_time,dram_time);
int mask = 0x00;
- if (gpgpu_cache_dl2_opt //when no-L2 it will never be L2's turn
+ if (m_memory_config->gpgpu_cache_dl2_opt //when no-L2 it will never be L2's turn
&& ( l2_time <= smallest) ) {
smallest = l2_time;
mask |= L2 ;
@@ -1411,181 +1318,114 @@ inline int next_clock_domain(void)
return mask;
}
-void gpu_sim_loop( int grid_num )
+unsigned long long g_single_step=0; // set this in gdb to single step the pipeline
+
+void gpgpu_sim::gpu_sim_loop()
{
int clock_mask = next_clock_domain();
// shader core loading (pop from ICNT into shader core) follows CORE clock
if (clock_mask & CORE ) {
- for (int i=0;i<gpu_n_tpc;i++) {
+ for (int i=0;i<gpu_n_tpc;i++)
fq_pop(i);
- }
}
- if (clock_mask & ICNT) {
- // pop from memory controller to interconnect
- static unsigned int *rt_size = NULL;
- if (!rt_size) rt_size = (unsigned int*) malloc ((gpu_n_tpc+gpu_n_mem)*sizeof(unsigned int));
- memset(rt_size, 0, (gpu_n_tpc+gpu_n_mem)*sizeof(unsigned int));
-
- for (unsigned i=0;i<gpu_n_mem;i++) {
-
- mem_fetch_t* mf;
-
- mf = (mem_fetch_t*) mem_ctrl_top(i); //(returns L2_top or DRAM returnq top)
-
- if (mf) {
- mf->source_node = mem2device(i);
- assert( mf->type != RD_REQ && mf->type != WT_REQ ); // never should a request come out from L2 or dram
- if (!mf->write) {
- int return_dev = -1;
- return_dev = mf->sid / gpu_concentration;
- assert(return_dev != -1);
- // check icnt resource for READ data return
- rt_size[return_dev] = mf->nbytes_L1;
- if ( icnt_has_buffer( mem2device(i), rt_size) ) {
- if (mf->mshr) mshr_update_status(mf->mshr,IN_ICNT2SHADER);
- memlatstat_icnt2sh_push(mf);
- time_vector_update(mf->mshr->insts[0].uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ);
- icnt_push( mem2device(i), return_dev, mf, mf->nbytes_L1);
- mem_ctrl_pop(i);
- } else {
- gpu_stall_icnt2sh++;
- }
- rt_size[return_dev] = 0; // clean up for the next dram_pop
- } else {
- time_vector_update(mf->request_uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,WT_REQ ) ;
- mem_ctrl_pop(i);
- free(mf);
- freed_L1write_mfs++;
- gpgpu_n_processed_writes++;
+ if (clock_mask & ICNT) {
+ // pop from memory controller to interconnect
+ for (unsigned i=0;i<m_n_mem;i++) {
+ mem_fetch* mf = m_memory_partition_unit[i]->top();
+ if (mf) {
+ assert( mf->type != RD_REQ && mf->type != WT_REQ );
+ unsigned response_size = mf->m_write?mf->nbytes_L1:WRITE_PACKET_SIZE;
+ if ( icnt_has_buffer( mem2device(i), response_size ) ) {
+ if (!mf->m_write) {
+ if (mf->mshr) mf->mshr->set_status(IN_ICNT2SHADER);
+ m_memory_stats->memlatstat_icnt2sh_push(mf);
+ if ( mf->mshr && mf->mshr->has_inst() )
+ time_vector_update(mf->mshr->get_insts_uid(),MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ);
+ } else {
+ time_vector_update(mf->request_uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,WT_REQ ) ;
+ freed_L1write_mfs++;
+ gpgpu_n_processed_writes++;
+ }
+ int return_dev = mf->sid / gpu_concentration;
+ icnt_push( mem2device(i), return_dev, mf, response_size );
+ m_memory_partition_unit[i]->pop();
+ } else {
+ gpu_stall_icnt2sh++;
+ }
}
- }
- }
- }
+ }
+ }
if (clock_mask & DRAM) {
- for (unsigned i=0;i<gpu_n_mem;i++) {
- get_dram_output ( dram[i] );
- }
- // Issue the dram command (scheduler + delay model)
- for (unsigned i=0;i<gpu_n_mem;i++) {
- dram_issueCMD(dram[i]);
+ for (unsigned i=0;i<m_n_mem;i++) {
+ m_memory_partition_unit[i]->issueCMD(); // Issue the dram command (scheduler + delay model)
}
- dram_log(SAMPLELOG);
}
// L2 operations follow L2 clock domain
if (clock_mask & L2) {
- for (unsigned i=0;i<gpu_n_mem;i++) {
- L2c_process_dram_output ( dram[i], i ); // pop from dram
- L2c_push_miss_to_dram ( dram[i] ); //push to dram
- L2c_service_mem_req ( dram[i], i ); // pop(push) from(to) icnt2l2(l2toicnt) queues; service l2 requests
- }
- if (gpgpu_cache_dl2_opt) { // L2 cache enabled
- for (unsigned i=0;i<gpu_n_mem;i++) {
- L2c_update_stat( dram[i] );
- }
- }
- if (gpgpu_cache_dl2_opt) { //take a sample of l2c queue lengths
- L2c_log(SAMPLELOG);
- }
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->cache_cycle();
}
if (clock_mask & ICNT) {
- // pop memory request from ICNT and
- // push it to a dram delay queue
- for (unsigned i=0;i<gpu_n_mem;i++) {
- // Push memory request to dram delay queue if mem_ctrl is not full
- if ( mem_ctrl_full(i) ) {
+ for (unsigned i=0;i<m_n_mem;i++) {
+ if ( m_memory_partition_unit[i]->full() ) {
+ gpu_stall_dramfull++;
continue;
}
-
- mem_fetch_t* mf;
- mf = (mem_fetch_t*) icnt_pop( mem2device(i) );
-
- if (mf) {
-
- dram_delay_t dram_delay;
- dram_delay.mf = mf;
- dram_delay.ready_cycle = gpu_sim_cycle + gpu_tot_sim_cycle + 115; // Add 115*4=460 delay cycles
- dram_delay_queues[i].push(dram_delay);
- }
- }
-
- // pop memory request from dram delay queue and
- // push it to the proper memory controller (L2 or DRAM controller)
- for (unsigned i=0;i<gpu_n_mem;i++) {
- if(!dram_delay_queues[i].empty() && dram_delay_queues[i].front().ready_cycle <= gpu_sim_cycle + gpu_tot_sim_cycle) {
- if ( mem_ctrl_full(i) ) {
- gpu_stall_dramfull++;
- continue;
- }
- mem_fetch_t* mf = dram_delay_queues[i].front().mf;
- if (mf->type==RD_REQ) {
- time_vector_update(mf->mshr->insts[0].uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ;
- } else {
- time_vector_update(mf->request_uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ;
- }
- memlatstat_icnt2mem_pop(mf);
- mem_ctrl_push( i, mf );
-
- dram_delay_queues[i].pop();
- }
+ // move memory request from interconnect into memory partition (if memory controller not backed up)
+ mem_fetch* mf = (mem_fetch*) icnt_pop( mem2device(i) );
+ m_memory_partition_unit[i]->push( mf, gpu_sim_cycle + gpu_tot_sim_cycle );
}
-
- icnt_transfer( );
+ icnt_transfer();
}
if (clock_mask & CORE) {
// L1 cache + shader core pipeline stages
- for (unsigned i=0;i<gpu_n_shader;i++) {
- if (sc[i]->not_completed || more_thread)
- shader_cycle(sc[i], i, grid_num);
- sc[i]->gpu_cycle++;
+ 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) )
+ m_sc[i]->cycle_gt200();
+ }
+ }
+ if( g_single_step && ((gpu_sim_cycle+gpu_tot_sim_cycle) >= g_single_step) ) {
+ asm("int $03");
}
gpu_sim_cycle++;
if( g_interactive_debugger_enabled )
gpgpu_debug();
- for (unsigned i=0;i<gpu_n_shader && more_thread;i++) {
- if (gpgpu_spread_blocks_across_cores) {
- int cta_issue_count = 1;
- if ( ( (unsigned) (sc[i]->n_active_cta + cta_issue_count) <= max_cta_per_shader(sc[i]) )
- && g_total_cta_left ) {
- int j;
- for (j=0;j<cta_issue_count;j++) {
- issue_block2core(sc[i], grid_num);
- }
- if (!g_total_cta_left) {
- more_thread = 0;
- }
- assert( g_total_cta_left > -1 );
- }
- } else {
- if (!(sc[i]->not_completed))
- more_thread = issue_block2core(sc[i], grid_num);
+ for (unsigned i=0;i<m_n_shader && more_thread;i++) {
+ if ( ( (m_sc[i]->get_n_active_cta()+1) <= m_sc[i]->max_cta(m_the_kernel.entry()) ) && g_total_cta_left ) {
+ m_sc[i]->issue_block2core( m_the_kernel );
+ if (!g_total_cta_left)
+ more_thread = 0;
+ assert( g_total_cta_left > -1 );
}
}
-
// Flush the caches once all of threads are completed.
if (gpgpu_flush_cache) {
int all_threads_complete = 1 ;
- for (unsigned i=0;i<gpu_n_shader;i++) {
- if (sc[i]->not_completed == 0) {
- shader_cache_flush(sc[i]);
+ for (unsigned i=0;i<m_n_shader;i++) {
+ if (m_sc[i]->get_not_completed() == 0) {
+ m_sc[i]->cache_flush();
} else {
all_threads_complete = 0 ;
}
}
if (all_threads_complete) {
printf("Flushed L1 caches...\n");
- if (gpgpu_cache_dl2_opt) {
+ if (m_memory_config->gpgpu_cache_dl2_opt) {
int dlc = 0;
- for (unsigned i=0;i<gpu_n_mem;i++) {
- dlc = L2c_cache_flush(dram[i]);
- printf("Dirty lines flushed from L2 %d is %d \n", i, dlc );
+ for (unsigned i=0;i<m_n_mem;i++) {
+ dlc = m_memory_partition_unit[i]->L2c_cache_flush();
+ printf("Dirty lines flushed from L2 %d is %d\n", i, dlc );
}
}
}
@@ -1607,23 +1447,22 @@ void gpu_sim_loop( int grid_num )
(unsigned)days,(unsigned)hrs,(unsigned)minutes,(unsigned)sec,
ctime(&curr_time));
fflush(stdout);
- memlatstat_lat_pw();
+ m_memory_stats->memlatstat_lat_pw(m_n_shader,m_shader_config->n_thread_per_shader,m_shader_config->warp_size);
visualizer_printstat();
if (gpgpu_runtime_stat && (gpu_runtime_stat_flag != 0) ) {
if (gpu_runtime_stat_flag & GPU_RSTAT_BW_STAT) {
- for (unsigned i=0;i<gpu_n_mem;i++) {
- dram_print_stat(dram[i],stdout);
- }
- printf("maxmrqlatency = %d \n", max_mrq_latency);
- printf("maxmflatency = %d \n", max_mf_latency);
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->print_stat(stdout);
+ 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<gpu_n_shader;i++) {
+ for (unsigned i=0;i<m_n_shader;i++) {
printf("%u ",acc_dyn_pcs[i]);
}
printf("\n");
- print_thread_pc( stdout );
+ print_thread_pc( stdout, m_n_shader );
}
if (gpu_runtime_stat_flag & GPU_RSTAT_SHD_INFO) {
shader_print_runtime_stat( stdout );
@@ -1635,25 +1474,24 @@ void gpu_sim_loop( int grid_num )
shader_print_l1_miss_stat( stdout );
}
if (gpu_runtime_stat_flag & GPU_RSTAT_PDOM ) {
- if (pdom_sched_type) {
- printf ("pdom_original_warps_count %d \n",n_pdom_sc_orig_stat );
- printf ("pdom_single_warps_count %d \n",n_pdom_sc_single_stat );
+ if (m_pdom_sched_type) {
+ printf ("pdom_original_warps_count %d \n",m_shader_stats->n_pdom_sc_orig_stat );
+ printf ("pdom_single_warps_count %d \n",m_shader_stats->n_pdom_sc_single_stat );
}
}
if (gpu_runtime_stat_flag & GPU_RSTAT_SCHED ) {
printf("Average Num. Warps Issuable per Shader:\n");
- for (unsigned i=0;i<gpu_n_shader;i++) {
- printf("%2.2f ", (float) num_warps_issuable_pershader[i]/ gpu_stat_sample_freq);
- num_warps_issuable_pershader[i] = 0;
+ for (unsigned i=0;i<m_n_shader;i++) {
+ printf("%2.2f ", (float) m_shader_stats->num_warps_issuable_pershader[i]/ gpu_stat_sample_freq);
+ m_shader_stats->num_warps_issuable_pershader[i] = 0;
}
printf("\n");
}
}
}
- for (unsigned i=0;i<gpu_n_mem;i++) {
- acc_mrq_length[i] += dram_que_length(dram[i]);
- }
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_stats->acc_mrq_length[i] += m_memory_partition_unit[i]->dram_que_length();
if (!(gpu_sim_cycle % 20000)) {
// deadlock detection
if (gpu_deadlock_detect && gpu_sim_insn == last_gpu_sim_insn) {
@@ -1667,56 +1505,21 @@ void gpu_sim_loop( int grid_num )
}
}
-void dump_regs(unsigned sid, unsigned tid)
+void shader_core_ctx::dump_istream_state( FILE *fout )
{
- if ( sid >= gpu_n_shader ) {
- printf("shader %u is out of range\n",sid);
- return;
- }
- if ( tid >= gpu_n_thread_per_shader ) {
- printf("thread %u is out of range\n",tid);
- return;
- }
-
- shader_core_ctx_t *s = sc[sid];
-
- ptx_dump_regs( s->thread[tid].ptx_thd_info );
+ fprintf(fout, "\n");
+ for (unsigned w=0; w < m_config->max_warps_per_shader; w++ )
+ m_warp[w].print(fout);
}
-void shader_dump_istream_state(shader_core_ctx_t *shader, FILE *fout )
-{
- fprintf( fout, "\n");
- for (unsigned t=0; t < gpu_n_thread_per_shader/warp_size; t++ ) {
- int tid = t*warp_size;
- if ( shader->warp[t].n_completed < warp_size ) {
- fprintf( fout, " %u:%3u (w%02u) fetch state = c:%u a4f:%u bw:%u (completed: ", shader->sid, tid, t,
- shader->warp[t].n_completed,
- shader->warp[t].n_avail4fetch,
- shader->warp[t].n_waiting_at_barrier );
-
- for (unsigned i = tid; i < (t+1)*warp_size; i++ ) {
- if ( ptx_thread_done(shader->thread[i].ptx_thd_info) ) {
- fprintf(fout,"1");
- } else {
- fprintf(fout,"0");
- }
- if ( (((i+1)%4) == 0) && (i+1) < (t+1)*warp_size ) {
- fprintf(fout,",");
- }
- }
- fprintf(fout,")\n");
- }
- }
-}
-
-void dump_pipeline_impl( int mask, int s, int m )
+void gpgpu_sim::dump_pipeline( int mask, int s, int m ) const
{
/*
You may want to use this function while running GPGPU-Sim in gdb.
One way to do that is add the following to your .gdbinit file:
define dp
- call dump_pipeline_impl((0x40|0x4|0x1),$arg0,0)
+ call g_the_gpu.dump_pipeline_impl((0x40|0x4|0x1),$arg0,0)
end
Then, typing "dp 3" will show the contents of the pipeline for shader core 3.
@@ -1724,25 +1527,26 @@ void dump_pipeline_impl( int mask, int s, int m )
printf("Dumping pipeline state...\n");
if(!mask) mask = 0xFFFFFFFF;
- for (unsigned i=0;i<gpu_n_shader;i++) {
+ for (unsigned i=0;i<m_n_shader;i++) {
if(s != -1) {
i = s;
}
- if(mask&1) shader_display_pipeline(sc[i], stdout, 1, mask & 0x2E );
- if(mask&0x40) shader_dump_istream_state(sc[i], stdout);
- if(mask&0x100) mshr_print(stdout, sc[i]);
+ if(mask&1) m_sc[i]->display_pipeline(stdout, 1, mask & 0x2E );
+ if (!strcmp("GPGPUSIM_ORIG",m_shader_config->pipeline_model) )
+ if(mask&0x40) m_sc[i]->dump_istream_state(stdout);
+ if(mask&0x100) m_sc[i]->mshr_print(stdout, mask);
if(s != -1) {
break;
}
}
if(mask&0x10000) {
- for (unsigned i=0;i<gpu_n_mem;i++) {
+ for (unsigned i=0;i<m_n_mem;i++) {
if(m != -1) {
i=m;
}
printf("DRAM / memory controller %u:\n", i);
- if(mask&0x100000) dram_print_stat(dram[i],stdout);
- if(mask&0x1000000) dram_visualize( dram[i] );
+ if(mask&0x100000) m_memory_partition_unit[i]->print_stat(stdout);
+ if(mask&0x1000000) m_memory_partition_unit[i]->visualize();
if(m != -1) {
break;
}
@@ -1751,8 +1555,7 @@ void dump_pipeline_impl( int mask, int s, int m )
fflush(stdout);
}
-void dump_pipeline()
+void memory_partition_unit::visualizer_print( gzFile visualizer_file )
{
- dump_pipeline_impl(0,-1,-1);
+ m_dram->visualizer_print(visualizer_file);
}
-
diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h
index 45d65e3..5bb9875 100644
--- a/src/gpgpu-sim/gpu-sim.h
+++ b/src/gpgpu-sim/gpu-sim.h
@@ -69,6 +69,10 @@
#ifndef GPU_SIM_H
#define GPU_SIM_H
+#include "../abstract_hardware_model.h"
+#include <list>
+#include <stdio.h>
+
// constants for statistics printouts
#define GPU_RSTAT_SHD_INFO 0x1
#define GPU_RSTAT_BW_STAT 0x2
@@ -88,88 +92,289 @@
// clock constants
#define MhZ *1000000
-extern void init_gpu();
-extern void gpu_reg_options(class OptionParser * opp);
-extern unsigned int run_gpu_sim(int grid_num);
-extern unsigned int get_converge_point(unsigned int pc, void *thd);
-extern void gpu_print_stat();
-extern int mem_ctrl_full( int mc_id );
-extern void dramqueue_latency_log_dump();
-extern void dump_pipeline_impl( int mask, int s, int m );
+#define CREATELOG 111
+#define SAMPLELOG 222
+#define DUMPLOG 333
+
+void increment_x_then_y_then_z( dim3 &i, const dim3 &bound);
+
+class kernel_info_t {
+public:
+ kernel_info_t()
+ {
+ m_valid=false;
+ m_kernel_entry=NULL;
+ }
+ kernel_info_t( dim3 gridDim, dim3 blockDim, class function_info *entry )
+ {
+ m_valid=true;
+ m_kernel_entry=entry;
+ m_grid_dim=gridDim;
+ m_block_dim=blockDim;
+ m_next_cta.x=0;
+ m_next_cta.y=0;
+ m_next_cta.z=0;
+ m_next_tid=m_next_cta;
+ }
+
+ class function_info *entry() { return m_kernel_entry; }
+
+ size_t num_blocks() const
+ {
+ return m_grid_dim.x * m_grid_dim.y * m_grid_dim.z;
+ }
+
+ size_t threads_per_cta() const
+ {
+ return m_block_dim.x * m_block_dim.y * m_block_dim.z;
+ }
+
+ dim3 get_grid_dim() const { return m_grid_dim; }
+ dim3 get_cta_dim() const { return m_block_dim; }
+
+ void increment_cta_id()
+ {
+ increment_x_then_y_then_z(m_next_cta,m_grid_dim);
+ m_next_tid.x=0;
+ m_next_tid.y=0;
+ m_next_tid.z=0;
+ }
+ dim3 get_next_cta_id() const { return m_next_cta; }
+ bool no_more_ctas_to_run() const
+ {
+ return (m_next_cta.x >= m_grid_dim.x || m_next_cta.y >= m_grid_dim.y || m_next_cta.z >= m_grid_dim.z );
+ }
+
+ void increment_thread_id() { increment_x_then_y_then_z(m_next_tid,m_block_dim); }
+ dim3 get_next_thread_id_3d() const { return m_next_tid; }
+ unsigned get_next_thread_id() const
+ {
+ return m_next_tid.x + m_block_dim.x*m_next_tid.y + m_block_dim.x*m_block_dim.y*m_next_tid.z;
+ }
+ bool more_threads_in_cta() const
+ {
+ return m_next_tid.z < m_block_dim.z && m_next_tid.y < m_block_dim.y && m_next_tid.z < m_block_dim.x;
+ }
+
+private:
+ bool m_valid;
+ class function_info *m_kernel_entry;
+
+ dim3 m_grid_dim;
+ dim3 m_block_dim;
+ dim3 m_next_cta;
+ dim3 m_next_tid;
+};
+
+enum divergence_support_t {
+ POST_DOMINATOR = 1,
+ MIMD = 2,
+ DWF = 3,
+ NUM_SIMD_MODEL
+};
+
+struct shader_core_config
+{
+ char *pipeline_model;
+ unsigned warp_size;
+ bool gpgpu_perfect_mem;
+ enum divergence_support_t model;
+ unsigned n_thread_per_shader;
+ unsigned max_warps_per_shader;
+ unsigned max_cta_per_core; //Limit on number of concurrent CTAs in shader core
+ unsigned pdom_sched_type;
+ bool gpgpu_no_dl1;
+ char *gpgpu_cache_texl1_opt;
+ char *gpgpu_cache_constl1_opt;
+ char *gpgpu_cache_dl1_opt;
+ char *gpgpu_cache_il1_opt;
+ unsigned n_mshr_per_shader;
+ bool gpgpu_dwf_reg_bankconflict;
+ 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
+ unsigned gpgpu_shmem_size;
+ unsigned gpgpu_shader_registers;
+ int gpgpu_warpdistro_shader;
+ int gpgpu_interwarp_mshr_merge;
+ int gpgpu_n_shmem_bank;
+ int gpgpu_n_cache_bank;
+ int gpgpu_shmem_port_per_bank;
+ int gpgpu_cache_port_per_bank;
+ int gpgpu_const_port_per_bank;
+ int gpgpu_shmem_pipe_speedup;
+ unsigned gpgpu_num_reg_banks;
+ unsigned gpu_max_cta_per_shader; // TODO: modify this for fermi... computed based upon kernel
+ // resource usage; used in shader_core_ctx::translate_local_memaddr
+ bool gpgpu_reg_bank_use_warp_id;
+ 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 {
+ DRAM_FIFO=0,
+ DRAM_IDEAL_FAST=1
+};
+
+struct memory_config {
+ char *gpgpu_cache_dl2_opt;
+ char *gpgpu_dram_timing_opt;
+ char *gpgpu_L2_queue_config;
+ bool gpgpu_l2_readoverwrite;
+ bool l2_ideal;
+ unsigned gpgpu_dram_sched_queue_size;
+ unsigned int gpu_mem_n_bk;
+ enum dram_ctrl_t scheduler_type;
+ bool gpgpu_memlatency_stat;
+ unsigned gpgpu_dram_buswidth;
+ unsigned gpgpu_dram_burst_length;
+};
+
+// global 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;
+
+extern bool g_interactive_debugger_enabled;
+
+extern int g_ptx_inst_debug_to_file;
+extern char* g_ptx_inst_debug_file;
+extern int g_ptx_inst_debug_thread_uid;
+
+
+
+
+class gpgpu_sim {
+public:
+ gpgpu_sim();
+
+ void reg_options(class OptionParser * opp);
+ void init_gpu();
+ void set_prop( struct cudaDeviceProp *prop );
+
+ void launch( kernel_info_t &kinfo );
+ void next_grid( unsigned &grid_num, class function_info *&entry );
+
+ unsigned run_gpu_sim();
+
+ unsigned get_L2_linesize() const;
+
+ unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid );
+ void decrement_atomic_count( unsigned sid, unsigned wid );
+ void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc );
+ const kernel_info_t &the_kernel() const { return m_the_kernel; }
+
+ int shared_mem_size() const;
+ int num_registers_per_core() const;
+ int wrp_size() const;
+ int shader_clock() const;
+ const struct cudaDeviceProp *get_prop() const;
+ enum divergence_support_t simd_model() const;
+
+ unsigned num_shader() const { return m_n_shader; }
+ unsigned threads_per_core() const;
+ void mem_instruction_stats( class inst_t* warp);
+ int issue_mf_from_fq(class mem_fetch *mf);
+
+ void gpu_print_stat() const;
+ void dump_pipeline( int mask, int s, int m ) const;
+
+private:
+ // clocks
+ void init_clock_domains(void);
+ void reinit_clock_domains(void);
+ int next_clock_domain(void);
+
+ unsigned char check_icnt_has_buffer(unsigned long long int addr, int bsize, int sid );
+ void gpu_sim_loop();
+ void fq_pop(int tpc_id);
+ void L2c_options(class OptionParser *opp);
+ void L2c_print_cache_stat() const;
+ void L2c_print_debug();
+ void L2c_latency_log_dump();
+ void shader_print_runtime_stat( FILE *fout );
+ void shader_print_l1_miss_stat( FILE *fout );
+ void shader_print_accstats( FILE* fout ) const;
+ void visualizer_printstat();
+ void print_shader_cycle_distro( FILE *fout ) const;
+
+ void gpgpu_debug();
+
+ // data
+ class shader_core_ctx **m_sc;
+ class memory_partition_unit **m_memory_partition_unit;
+
+ unsigned m_grid_num;
+ kernel_info_t m_the_kernel;
+ std::list<kernel_info_t> m_running_kernels;
+
+ // clock domains - frequency
+ double core_freq;
+ double icnt_freq;
+ double dram_freq;
+ double l2_freq;
+
+ // clock period
+ double core_period;
+ double icnt_period;
+ double dram_period;
+ double l2_period;
+
+ // time of next rising edge
+ double core_time;
+ double icnt_time;
+ double dram_time;
+ double l2_time;
+
+ // configuration parameters
+ bool m_options_set;
+ struct cudaDeviceProp *m_cuda_properties;
+ struct shader_core_config *m_shader_config;
+ struct memory_config *m_memory_config;
+ unsigned int m_n_shader;
+ unsigned int m_n_mem;
+ int gpu_concentration;
+
+ int m_pdom_sched_type;
+
+ struct shader_core_stats *m_shader_stats;
+ class memory_stats_t *m_memory_stats;
+public:
+ unsigned long long gpu_sim_insn_last_update;
+};
+
+// global counters
-extern unsigned int L1_write_miss;
-extern unsigned int L1_read_miss;
-extern unsigned int L1_texture_miss;
-extern unsigned int L1_const_miss;
-extern unsigned int L1_write_hit_on_miss;
-extern unsigned int L1_writeback;
-extern unsigned int L1_const_miss;
-extern bool gpgpu_perfect_mem;
-extern bool gpgpu_no_dl1;
-extern char *gpgpu_cache_texl1_opt;
-extern char *gpgpu_cache_constl1_opt;
-extern char *gpgpu_cache_dl1_opt;
-extern unsigned int gpu_n_thread_per_shader;
-extern unsigned int gpu_n_mshr_per_shader;
-extern unsigned int gpu_n_shader;
-extern unsigned int gpu_n_mem;
-extern bool gpgpu_reg_bankconflict;
-extern int gpgpu_dram_sched_queue_size;
extern unsigned long long gpu_sim_cycle;
extern unsigned long long gpu_tot_sim_cycle;
extern unsigned long long gpu_sim_insn;
-extern unsigned int gpu_n_warp_per_shader;
+extern unsigned long long gpu_tot_sim_insn;
+extern unsigned g_next_mf_request_uid;
+
+// stats
+
extern unsigned int **max_conc_access2samerow;
extern unsigned int **max_servicetime2samerow;
extern unsigned int **row_access;
extern unsigned int **num_activates;
-extern struct dram_timing **dram;
-extern int *num_warps_issuable;
-extern int *num_warps_issuable_pershader;
-extern unsigned long long gpu_sim_insn_no_ld_const;
-extern unsigned long long gpu_sim_insn_last_update;
-extern unsigned long long gpu_completed_thread;
-extern class shader_core_ctx **sc;
-extern unsigned int gpgpu_pre_mem_stages;
-extern bool gpgpu_no_divg_load;
-extern bool gpgpu_thread_swizzling;
-extern bool gpgpu_strict_simd_wrbk;
-extern unsigned int warp_conflict_at_writeback;
-extern unsigned int gpgpu_commit_pc_beyond_two;
-extern bool gpgpu_spread_blocks_across_cores;
-extern int gpgpu_cflog_interval;
-extern unsigned int gpu_stall_by_MSHRwb;
-extern unsigned int gpu_stall_shd_mem;
-extern unsigned int gpu_stall_sh2icnt;
-extern bool gpgpu_operand_collector;
-extern int gpgpu_operand_collector_num_units;
-extern int gpgpu_operand_collector_num_units_sfu;
-extern int gpu_runtime_stat_flag;
-extern unsigned int *max_return_queue_length;
-extern int gpgpu_partial_write_mask;
-extern int gpgpu_n_mem_write_local;
-extern int gpgpu_n_mem_write_global;
-extern bool gpgpu_cache_wt_through;
-extern double core_freq;
-extern double icnt_freq;
-extern double dram_freq;
-extern double l2_freq;
-extern int pdom_sched_type;
-extern int n_pdom_sc_orig_stat;
-extern int n_pdom_sc_single_stat;
-extern bool gpgpu_cuda_sim;
-extern int gpgpu_mem_address_mask;
-extern bool g_interactive_debugger_enabled;
-extern unsigned int gpu_n_mem_per_ctrlr;
extern unsigned int **concurrent_row_access; //concurrent_row_access[dram chip id][bank id]
-extern unsigned long long gpu_tot_sim_insn;
+
extern unsigned int gpgpu_n_sent_writes;
extern unsigned int gpgpu_n_processed_writes;
-extern int gpgpu_simd_model;
-extern unsigned int gpu_mem_n_bk;
-extern unsigned g_next_mf_request_uid;
-extern int g_ptx_inst_debug_to_file;
-extern char* g_ptx_inst_debug_file;
-extern int g_ptx_inst_debug_thread_uid;
+extern unsigned made_write_mfs;
+extern unsigned made_read_mfs;
#endif
diff --git a/src/gpgpu-sim/icnt_wrapper.cc b/src/gpgpu-sim/icnt_wrapper.cc
index aa55110..25238f9 100644
--- a/src/gpgpu-sim/icnt_wrapper.cc
+++ b/src/gpgpu-sim/icnt_wrapper.cc
@@ -85,12 +85,12 @@ void icnt_reg_options( class OptionParser * opp )
option_parser_register(opp, "-inter_config_file", OPT_CSTR, &g_network_config_filename, "Interconnection network config file", "mesh");
}
-void icnt_init( unsigned int n_shader, unsigned int n_mem )
+void icnt_init( unsigned int n_shader, unsigned int n_mem, struct shader_core_config *shader_config )
{
switch (g_network_mode) {
case INTERSIM:
- init_interconnect(g_network_config_filename ,n_shader, n_mem);
+ init_interconnect(g_network_config_filename, n_shader, n_mem, shader_config );
icnt_has_buffer = interconnect_has_buffer;
icnt_push = interconnect_push;
icnt_pop = interconnect_pop;
diff --git a/src/gpgpu-sim/icnt_wrapper.h b/src/gpgpu-sim/icnt_wrapper.h
index 0961fc4..26e394b 100644
--- a/src/gpgpu-sim/icnt_wrapper.h
+++ b/src/gpgpu-sim/icnt_wrapper.h
@@ -68,7 +68,7 @@
#define ICNT_WRAPPER_H
// functional interface to the interconnect
-typedef int (*icnt_has_buffer_p)(unsigned int input, unsigned int *size);
+typedef int (*icnt_has_buffer_p)(unsigned int input, unsigned int size);
typedef void (*icnt_push_p)(unsigned int input, unsigned int output, void* data, unsigned int size);
typedef void* (*icnt_pop_p)(unsigned int output);
typedef void (*icnt_transfer_p)( );
@@ -88,7 +88,7 @@ enum network_mode {
N_NETWORK_MODE
};
-void icnt_init( unsigned int n_shader, unsigned int n_mem );
+void icnt_init( unsigned int n_shader, unsigned int n_mem, struct shader_core_config *shader_config );
void icnt_reg_options( class OptionParser * opp );
#endif
diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc
index f27c940..cbed2e9 100644
--- a/src/gpgpu-sim/l2cache.cc
+++ b/src/gpgpu-sim/l2cache.cc
@@ -1,10 +1,75 @@
+/*
+ * l2cache.cc
+ *
+ * Copyright (c) 2009 by Tor M. Aamodt and
+ * 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <list>
#include <set>
-#include "../tr1_hash_map.h" // for unordered_map failback
#include "../option_parser.h"
#include "mem_fetch.h"
@@ -15,137 +80,52 @@
#include "../intersim/statwraper.h"
#include "../abstract_hardware_model.h"
#include "gpu-sim.h"
+#include "shader.h"
+#include "mem_latency_stat.h"
-class L2c_mshr;
-class L2c_miss_tracker;
-class L2c_access_locality;
-
-mem_fetch_t* g_debug_mf = NULL;
-
-// L2 cache block (include the cache model + flow controls)
-struct L2cacheblk
-{
- shd_cache_t *L2cache;
-
- delay_queue *cbtoL2queue; //latency 10
- delay_queue *cbtoL2writequeue;
- delay_queue *dramtoL2queue; //latency 10
- delay_queue *dramtoL2writequeue;
- delay_queue *L2todramqueue; //latency 0
- delay_queue *L2todram_wbqueue;
- delay_queue *L2tocbqueue; //latency 0
-
- mem_fetch_t *L2request; //request currently being serviced by the L2 Cache
-
- L2c_mshr *m_mshr; // mshr model
- L2c_miss_tracker *m_missTracker; // tracker observing for redundant misses
- L2c_access_locality *m_accessLocality; // tracking true locality of L2 Cache access
-
- L2cacheblk(size_t linesize);
- ~L2cacheblk();
-};
+template class fifo_pipeline<mem_fetch>;
// external dependencies
extern unsigned long long int addrdec_mask[5];
-extern int gpgpu_dram_sched_queue_size;
extern unsigned made_write_mfs;
extern unsigned freed_L1write_mfs;
extern unsigned freed_L2write_mfs;
-void memlatstat_icnt2sh_push(mem_fetch_t *mf);
-void memlatstat_dram_access(mem_fetch_t *mf, unsigned dram_id, unsigned bank);
-void memlatstat_start(mem_fetch_t *mf);
-unsigned memlatstat_done(mem_fetch_t *mf);
+address_type L2c_mshr::cache_tag(const mem_fetch *mf) const
+{
+ return (mf->addr & ~(m_linesize - 1));
+}
+
+address_type L2c_miss_tracker::cache_tag(const mem_fetch *mf) const
+{
+ return (mf->addr & ~(m_linesize - 1));
+}
-// option
-char *gpgpu_L2_queue_config;
-bool gpgpu_l2_readoverwrite;
-bool l2_ideal;
+address_type L2c_access_locality::cache_tag(const mem_fetch *mf) const
+{
+ return (mf->addr & ~(m_linesize - 1));
+}
-void L2c_options(option_parser_t opp)
+void gpgpu_sim::L2c_options(option_parser_t opp)
{
- option_parser_register(opp, "-gpgpu_L2_queue", OPT_CSTR, &gpgpu_L2_queue_config,
+ option_parser_register(opp, "-gpgpu_L2_queue", OPT_CSTR, &m_memory_config->gpgpu_L2_queue_config,
"L2 data cache queue length and latency config",
"0:0:0:0:0:0:10:10");
- option_parser_register(opp, "-gpgpu_l2_readoverwrite", OPT_BOOL, &gpgpu_l2_readoverwrite,
+ option_parser_register(opp, "-gpgpu_l2_readoverwrite", OPT_BOOL, &m_memory_config->gpgpu_l2_readoverwrite,
"Prioritize read requests over write requests for L2",
"0");
- option_parser_register(opp, "-l2_ideal", OPT_BOOL, &l2_ideal,
+ option_parser_register(opp, "-l2_ideal", OPT_BOOL, &m_memory_config->l2_ideal,
"Use a ideal L2 cache that always hit",
"0");
}
-// stats
-unsigned L2_write_miss = 0;
-unsigned L2_write_hit = 0;
-unsigned L2_read_hit = 0;
-unsigned L2_read_miss = 0;
-unsigned int *L2_cbtoL2length;
-unsigned int *L2_cbtoL2writelength;
-unsigned int *L2_L2tocblength;
-unsigned int *L2_dramtoL2length;
-unsigned int *L2_dramtoL2writelength;
-unsigned int *L2_L2todramlength;
////////////////////////////////////////////////
// L2 MSHR model
-class L2c_mshr
-{
-private:
- typedef std::list<const mem_fetch_t*> mem_fetch_list;
- typedef tr1_hash_map<address_type, mem_fetch_list> L2missGroup;
- L2missGroup m_L2missgroup; // structure tracking redundant dram access
-
- struct active_chain {
- address_type cacheTag;
- mem_fetch_list *list;
- active_chain() : cacheTag(0xDEADBEEF), list(NULL) { }
- };
- active_chain m_active_mshr_chain;
- size_t m_linesize; // L2 cache line size
-
- const size_t m_n_entries; // total number of entries available
- size_t m_entries_used; // number of entries in use
-
- int m_n_miss;
- int m_n_miss_serviced_by_dram;
- int m_n_mshr_hits;
- size_t m_max_entries_used;
-
- address_type cache_tag(const mem_fetch_t *mf) const
- {
- // return mf->addr;
- return (mf->addr & ~(m_linesize - 1));
- }
-
-public:
- L2c_mshr(size_t linesize, size_t n_entries = 64)
- : m_linesize(linesize), m_n_entries(n_entries), m_entries_used(0),
- m_n_miss(0), m_n_miss_serviced_by_dram(0), m_n_mshr_hits(0), m_max_entries_used(0) { }
-
- // add a cache miss to MSHR, return true if this access is hit another existing entry and merges with it
- bool new_miss(const mem_fetch_t *mf);
-
- // notify MSHR that a new cache line has been fetched, activate the associated MSHR chain
- void miss_serviced(const mem_fetch_t *mf);
-
- // probe if there are pending hits left in this MSHR chain
- bool mshr_chain_empty();
-
- // peek the first entry in the active MSHR chain
- mem_fetch_t *mshr_chain_top();
-
- // pop the first entry in the active MSHR chain
- void mshr_chain_pop();
-
- void print(FILE *fout = stdout);
- void print_stat(FILE *fout = stdout);
-};
-
-bool L2c_mshr::new_miss(const mem_fetch_t *mf)
+bool L2c_mshr::new_miss(const mem_fetch *mf)
{
address_type cacheTag = cache_tag(mf);
mem_fetch_list &missGroup = m_L2missgroup[cacheTag];
@@ -163,7 +143,7 @@ bool L2c_mshr::new_miss(const mem_fetch_t *mf)
return mshr_hit;
}
-void L2c_mshr::miss_serviced(const mem_fetch_t *mf)
+void L2c_mshr::miss_serviced(const mem_fetch *mf)
{
assert(m_active_mshr_chain.list == NULL);
address_type cacheTag = cache_tag(mf);
@@ -185,12 +165,12 @@ bool L2c_mshr::mshr_chain_empty()
return (m_active_mshr_chain.list == NULL);
}
-mem_fetch_t *L2c_mshr::mshr_chain_top()
+mem_fetch *L2c_mshr::mshr_chain_top()
{
- const mem_fetch_t *mf = m_active_mshr_chain.list->back();
+ const mem_fetch *mf = m_active_mshr_chain.list->back();
assert(cache_tag(mf) == m_active_mshr_chain.cacheTag);
- return const_cast<mem_fetch_t*>(mf);
+ return const_cast<mem_fetch*>(mf);
}
void L2c_mshr::mshr_chain_pop()
@@ -218,7 +198,7 @@ void L2c_mshr::print(FILE *fout)
}
}
-void L2c_mshr::print_stat(FILE *fout)
+void L2c_mshr::print_stat(FILE *fout) const
{
fprintf(fout, "L2c MSHR: max_entry = %zu, n_miss = %d, n_mshr_hits = %d, n_serviced_by_dram %d\n",
m_max_entries_used, m_n_miss, m_n_mshr_hits, m_n_miss_serviced_by_dram);
@@ -226,36 +206,8 @@ void L2c_mshr::print_stat(FILE *fout)
////////////////////////////////////////////////
// track redundant dram access generated by L2 cache
-class L2c_miss_tracker
-{
-private:
- typedef std::set<mem_fetch_t*> mem_fetch_set;
- typedef tr1_hash_map<address_type, mem_fetch_set> L2missGroup;
- L2missGroup m_L2missgroup; // structure tracking redundant dram access
- size_t m_linesize; // L2 cache line size
-
- typedef tr1_hash_map<address_type, int> L2redundantCnt;
- L2redundantCnt m_L2redundantCnt;
-
- int m_totalL2redundantAcc;
-
- address_type cache_tag(const mem_fetch_t *mf) const
- {
- // return mf->addr;
- return (mf->addr & ~(m_linesize - 1));
- }
-public:
- L2c_miss_tracker(size_t linesize) : m_linesize(linesize), m_totalL2redundantAcc(0) { }
- void new_miss(mem_fetch_t *mf);
- void miss_serviced(mem_fetch_t *mf);
-
- void print(FILE *fout, bool brief = true);
- void print_stat(FILE *fout, bool brief = true);
-
-};
-
-void L2c_miss_tracker::new_miss(mem_fetch_t *mf)
+void L2c_miss_tracker::new_miss(mem_fetch *mf)
{
address_type cacheTag = cache_tag(mf);
mem_fetch_set &missGroup = m_L2missgroup[cacheTag];
@@ -268,7 +220,7 @@ void L2c_miss_tracker::new_miss(mem_fetch_t *mf)
missGroup.insert(mf);
}
-void L2c_miss_tracker::miss_serviced(mem_fetch_t *mf)
+void L2c_miss_tracker::miss_serviced(mem_fetch *mf)
{
address_type cacheTag = cache_tag(mf);
L2missGroup::iterator iMissGroup = m_L2missgroup.find(cacheTag);
@@ -295,12 +247,12 @@ void L2c_miss_tracker::print(FILE *fout, bool brief)
}
}
-void L2c_miss_tracker::print_stat(FILE *fout, bool brief)
+void L2c_miss_tracker::print_stat(FILE *fout, bool brief) const
{
fprintf(fout, "RedundantMiss = %d\n", m_totalL2redundantAcc);
if (brief == true) return;
fprintf(fout, " Detail:");
- for (L2redundantCnt::iterator iL2rc = m_L2redundantCnt.begin(); iL2rc != m_L2redundantCnt.end(); ++iL2rc) {
+ for (L2redundantCnt::const_iterator iL2rc = m_L2redundantCnt.begin(); iL2rc != m_L2redundantCnt.end(); ++iL2rc) {
fprintf(fout, "%#08x:%d ", iL2rc->first, iL2rc->second);
}
fprintf(fout, "\n");
@@ -308,76 +260,90 @@ void L2c_miss_tracker::print_stat(FILE *fout, bool brief)
////////////////////////////////////////////////
// track all locality of L2 cache access
-class L2c_access_locality
-{
-private:
- size_t m_linesize; // L2 cache line size
-
- typedef tr1_hash_map<address_type, int> L2accCnt;
- L2accCnt m_L2accCnt;
-
- int m_totalL2accAcc;
-
- address_type cache_tag(const mem_fetch_t *mf) const
- {
- // return mf->addr;
- return (mf->addr & ~(m_linesize - 1));
- }
-
-public:
- L2c_access_locality(size_t linesize) : m_linesize(linesize), m_totalL2accAcc(0) { }
- void access(mem_fetch_t *mf);
-
- void print_stat(FILE *fout, bool brief = true);
-
-};
-
-void L2c_access_locality::access(mem_fetch_t *mf)
+void L2c_access_locality::access(mem_fetch *mf)
{
address_type cacheTag = cache_tag(mf);
m_L2accCnt[cacheTag] += 1;
m_totalL2accAcc += 1;
}
-void L2c_access_locality::print_stat(FILE *fout, bool brief)
+void L2c_access_locality::print_stat(FILE *fout, bool brief) const
{
float access_locality = (float) m_totalL2accAcc / m_L2accCnt.size();
fprintf(fout, "Access Locality = %d / %zu (%f) \n", m_totalL2accAcc, m_L2accCnt.size(), access_locality);
if (brief == true) return;
fprintf(fout, " Detail:");
pow2_histogram locality_histo(" Hits");
- for (L2accCnt::iterator iL2rc = m_L2accCnt.begin(); iL2rc != m_L2accCnt.end(); ++iL2rc) {
+ for (L2accCnt::const_iterator iL2rc = m_L2accCnt.begin(); iL2rc != m_L2accCnt.end(); ++iL2rc) {
locality_histo.add2bin(iL2rc->second);
- // fprintf(fout, "%#08x:%d\n", iL2rc->first, iL2rc->second);
}
locality_histo.fprint(fout);
fprintf(fout, "\n");
}
-L2cacheblk::L2cacheblk(size_t linesize)
-: m_mshr(new L2c_mshr(linesize)),
- m_missTracker(new L2c_miss_tracker(linesize)),
- m_accessLocality(new L2c_access_locality(linesize))
-{ }
-
-L2cacheblk::~L2cacheblk()
+memory_partition_unit::~memory_partition_unit()
{
delete m_mshr;
delete m_missTracker;
delete m_accessLocality;
}
+void memory_partition_unit::set_stats( class memory_stats_t *stats )
+{
+ m_stats=stats;
+ m_dram->set_stats(stats);
+}
+
+void memory_partition_unit::cache_cycle()
+{
+ L2c_process_dram_output(); // pop from dram
+ L2c_push_miss_to_dram(); // push to dram
+ L2c_service_mem_req(); // pop(push) from(to) icnt2l2(l2toicnt) queues; service l2 requests
+ if (m_config->gpgpu_cache_dl2_opt) { // L2 cache enabled
+ L2c_update_stat();
+ L2c_log(SAMPLELOG);
+ }
+}
+
+unsigned memory_partition_unit::L2c_get_linesize()
+{
+ return L2cache->line_sz;
+}
+
+bool memory_partition_unit::full() const
+{
+ if (m_config->gpgpu_cache_dl2_opt) {
+ return cbtoL2queue->full() || cbtoL2writequeue->full();
+ } else {
+ return( m_config->gpgpu_dram_sched_queue_size && m_dram->full() );
+ }
+}
////////////////////////////////////////////////
// L2 access functions
// L2 Cache Creation
-void L2c_create ( dram_t* dram_p, const char* cache_opt )
+memory_partition_unit::memory_partition_unit( unsigned partition_id, struct memory_config *config )
{
- unsigned int shd_n_set;
- unsigned int shd_linesize;
- unsigned int shd_n_assoc;
- unsigned char shd_policy;
+ m_id = partition_id;
+ m_config=config;
+ m_stats=NULL;
+ m_dram = new dram_t(m_id, m_config);
+
+ char L2c_name[32];
+ snprintf(L2c_name, 32, "L2_%03d", m_id);
+
+ if( m_config->gpgpu_cache_dl2_opt ) {
+ L2cache = shd_cache_create(L2c_name,m_config->gpgpu_cache_dl2_opt, 16, ~addrdec_mask[CHIP], write_through);
+ m_mshr = new L2c_mshr(L2cache->line_sz);
+ m_missTracker = new L2c_miss_tracker(L2cache->line_sz);
+ m_accessLocality = new L2c_access_locality(L2cache->line_sz);
+ } else {
+ L2cache=NULL;
+ m_mshr=NULL;
+ m_missTracker=NULL;
+ m_accessLocality=NULL;
+ }
unsigned int L2c_cb_L2_length;
unsigned int L2c_cb_L2w_length;
@@ -388,173 +354,116 @@ void L2c_create ( dram_t* dram_p, const char* cache_opt )
unsigned int L2c_L2_cb_minlength;
unsigned int L2c_L2_dm_minlength;
- sscanf(cache_opt,"%d:%d:%d:%c",
- &shd_n_set, &shd_linesize, &shd_n_assoc, &shd_policy);
-
- L2cacheblk *p_L2c = new L2cacheblk(shd_linesize);
-
- char L2c_name[32];
- snprintf(L2c_name, 32, "L2c_%03d", dram_p->id);
- p_L2c->L2cache = shd_cache_create(L2c_name,
- shd_n_set, shd_n_assoc, shd_linesize,
- shd_policy, 16, ~addrdec_mask[CHIP],
- write_through); //write_through maintains old behavior for now
-
- sscanf(gpgpu_L2_queue_config,"%d:%d:%d:%d:%d:%d:%d:%d",
+ sscanf(m_config->gpgpu_L2_queue_config,"%d:%d:%d:%d:%d:%d:%d:%d",
&L2c_cb_L2_length, &L2c_cb_L2w_length, &L2c_L2_dm_length,
&L2c_dm_L2_length, &L2c_dm_L2w_length, &L2c_L2_cb_length,
&L2c_L2_cb_minlength, &L2c_L2_dm_minlength );
//(<name>,<latency>,<min_length>,<max_length>)
- p_L2c->cbtoL2queue = dq_create("cbtoL2queue", 0,0,L2c_cb_L2_length);
- p_L2c->cbtoL2writequeue = dq_create("cbtoL2writequeue", 0,0,L2c_cb_L2w_length);
- p_L2c->L2todramqueue = dq_create("L2todramqueue", 0,L2c_L2_dm_minlength,L2c_L2_dm_length);
- p_L2c->dramtoL2queue = dq_create("dramtoL2queue", 0,0,L2c_dm_L2_length);
- p_L2c->dramtoL2writequeue = dq_create("dramtoL2writequeue",0,0,L2c_dm_L2w_length);
- p_L2c->L2tocbqueue = dq_create("L2tocbqueue", 0,L2c_L2_cb_minlength,L2c_L2_cb_length);
-
- p_L2c->L2todram_wbqueue = dq_create("L2todram_wbqueue", 0,L2c_L2_dm_minlength,
- L2c_L2_dm_minlength + gpgpu_dram_sched_queue_size + L2c_dm_L2_length);
-
- p_L2c->L2request = NULL;
-
- assert(dram_p->m_L2cache == NULL);
- dram_p->m_L2cache = reinterpret_cast<void*>(p_L2c);
-}
-
-unsigned L2c_get_linesize( dram_t *dram_p )
-{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
- return p_L2c->L2cache->line_sz;
-}
-
-int L2c_full( dram_t *dram_p )
-{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
- return(dq_full(p_L2c->cbtoL2queue) || dq_full(p_L2c->cbtoL2writequeue));
-}
-
-void L2c_push( dram_t *dram_p, mem_fetch_t *mf )
-{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- if (gpgpu_l2_readoverwrite && mf->write)
- dq_push(p_L2c->cbtoL2writequeue, mf);
- else
- dq_push(p_L2c->cbtoL2queue, mf);
- p_L2c->m_accessLocality->access(mf);
- if (mf->mshr) mshr_update_status(mf->mshr, IN_CBTOL2QUEUE);
+ cbtoL2queue = new fifo_pipeline<mem_fetch>("cbtoL2queue", 0,L2c_cb_L2_length, gpu_sim_cycle);
+ cbtoL2writequeue = new fifo_pipeline<mem_fetch>("cbtoL2writequeue", 0,L2c_cb_L2w_length, gpu_sim_cycle);
+ L2todramqueue = new fifo_pipeline<mem_fetch>("L2todramqueue", L2c_L2_dm_minlength, L2c_L2_dm_length, gpu_sim_cycle);
+ dramtoL2queue = new fifo_pipeline<mem_fetch>("dramtoL2queue", 0,L2c_dm_L2_length, gpu_sim_cycle);
+ dramtoL2writequeue = new fifo_pipeline<mem_fetch>("dramtoL2writequeue",0,L2c_dm_L2w_length, gpu_sim_cycle);
+ L2tocbqueue = new fifo_pipeline<mem_fetch>("L2tocbqueue", L2c_L2_cb_minlength, L2c_L2_cb_length, gpu_sim_cycle);
+ L2todram_wbqueue = new fifo_pipeline<mem_fetch>("L2todram_wbqueue", L2c_L2_dm_minlength, L2c_L2_dm_minlength + m_config->gpgpu_dram_sched_queue_size + L2c_dm_L2_length, gpu_sim_cycle);
+ L2request = NULL;
+ L2dramout = NULL;
+ wb_addr=-1;
+ if (m_config->gpgpu_cache_dl2_opt && 1) {
+ cbtol2_Dist = StatCreate("cbtoL2",1, cbtoL2queue->get_max_len());
+ cbtoL2wr_Dist = StatCreate("cbtoL2write",1, cbtoL2writequeue->get_max_len());
+ L2tocb_Dist = StatCreate("L2tocb",1, L2tocbqueue->get_max_len());
+ dramtoL2_Dist = StatCreate("dramtoL2",1, dramtoL2queue->get_max_len());
+ dramtoL2wr_Dist = StatCreate("dramtoL2write",1, dramtoL2writequeue->get_max_len());
+ L2todram_Dist = StatCreate("L2todram",1, L2todramqueue->get_max_len());
+ L2todram_wb_Dist = StatCreate("L2todram_wb",1, L2todram_wbqueue->get_max_len());
+ } else {
+ cbtol2_Dist = NULL;
+ cbtoL2wr_Dist = NULL;
+ L2tocb_Dist = NULL;
+ dramtoL2_Dist = NULL;
+ dramtoL2wr_Dist = NULL;
+ L2todram_Dist = NULL;
+ L2todram_wb_Dist = NULL;
+ }
}
-mem_fetch_t* L2c_pop( dram_t *dram_p )
+mem_fetch* memory_partition_unit::L2c_pop( dram_t *dram_p )
{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
+ assert(dram_p->m_memory_partition_unit != NULL);
+ memory_partition_unit *p_L2c = reinterpret_cast<memory_partition_unit*>(dram_p->m_memory_partition_unit);
- mem_fetch_t *mf;
- mf = (mem_fetch_t*)dq_pop(p_L2c->L2tocbqueue);
+ mem_fetch *mf;
+ mf = p_L2c->L2tocbqueue->pop(gpu_sim_cycle);
return mf;
}
-mem_fetch_t* L2c_top( dram_t *dram_p )
-{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- return (mem_fetch_t*)dq_top(p_L2c->L2tocbqueue);
-}
-
-void L2c_qlen ( dram_t *dram_p )
-{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- printf("\n");
- printf("cb->L2{%d}\tcb->L2w{%d}\tL2->cb{%d}\n",
- p_L2c->cbtoL2queue->length,
- p_L2c->cbtoL2writequeue->length,
- p_L2c->L2tocbqueue->length);
- printf("dm->L2{%d}\tdm->L2w{%d}\tL2->dm{%d}\tL2->wb_dm{%d}\n",
- p_L2c->dramtoL2queue->length,
- p_L2c->dramtoL2writequeue->length,
- p_L2c->L2todramqueue->length,
- p_L2c->L2todram_wbqueue->length);
-}
-
// service memory request in icnt-to-L2 queue, writing to L2 as necessary
// (if L2 writeback miss, writeback to memory)
-void L2c_service_mem_req ( dram_t* dram_p, int dm_id )
+void memory_partition_unit::L2c_service_mem_req()
{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- mem_fetch_t* mf;
-
- if (!p_L2c->L2request) {
+ if (!L2request) {
//if not servicing L2 cache request..
- p_L2c->L2request = (mem_fetch_t*) dq_pop(p_L2c->cbtoL2queue); //..then get one
- if (!p_L2c->L2request) {
- p_L2c->L2request = (mem_fetch_t*) dq_pop(p_L2c->cbtoL2writequeue);
- }
+ L2request = cbtoL2queue->pop(gpu_sim_cycle); //..then get one
+ if (!L2request)
+ L2request = cbtoL2writequeue->pop(gpu_sim_cycle);
}
- mf = p_L2c->L2request;
+ mem_fetch* mf = L2request;
if (!mf) return;
switch (mf->type) {
case RD_REQ:
case WT_REQ: {
- shd_cache_line_t *hit_cacheline = shd_cache_access(p_L2c->L2cache,
+ shd_cache_line_t *hit_cacheline = shd_cache_access(L2cache,
mf->addr,
- 4, mf->write,
+ 4, mf->m_write,
gpu_sim_cycle);
- if (hit_cacheline || l2_ideal) { //L2 Cache Hit; reads are sent as a single command and need to be stored
- if (!mf->write) { //L2 Cache Read
- if ( dq_full(p_L2c->L2tocbqueue) ) {
- p_L2c->L2cache->access--;
+ if (hit_cacheline || m_config->l2_ideal) { //L2 Cache Hit; reads are sent as a single command and need to be stored
+ if (!mf->m_write) { //L2 Cache Read
+ if ( L2tocbqueue->full() ) {
+ L2cache->access--;
} else {
mf->type = REPLY_DATA;
- dq_push(p_L2c->L2tocbqueue, mf);
+ L2tocbqueue->push(mf,gpu_sim_cycle);
// at this point, should first check if earlier L2 miss is ready to be serviced
// if so, service earlier L2 miss first
- p_L2c->L2request = NULL; //finished servicing
- L2_read_hit++;
- memlatstat_icnt2sh_push(mf);
- if (mf->mshr) mshr_update_status(mf->mshr, IN_L2TOCBQUEUE_HIT);
+ L2request = NULL; //finished servicing
+ m_stats->L2_read_hit++;
+ m_stats->memlatstat_icnt2sh_push(mf);
+ if (mf->mshr) mf->mshr->set_status(IN_L2TOCBQUEUE_HIT);
}
} else { //L2 Cache Write aka servicing L1 Writeback
- p_L2c->L2request = NULL;
- L2_write_hit++;
+ L2request = NULL;
+ m_stats->L2_write_hit++;
freed_L1write_mfs++;
free(mf); //writeback from L1 successful
gpgpu_n_processed_writes++;
}
} else {
// L2 Cache Miss; issue commands accordingly
- if ( dq_full(p_L2c->L2todramqueue) ) {
- p_L2c->L2cache->miss--;
- p_L2c->L2cache->access--;
+ if ( L2todramqueue->full() ) {
+ L2cache->miss--;
+ L2cache->access--;
} else {
// if a miss hit the mshr, that means there is another inflight request for the same data
// this miss just need to access the cache later when this request is serviced
- bool mshr_hit = p_L2c->m_mshr->new_miss(mf);
+ bool mshr_hit = m_mshr->new_miss(mf);
if (not mshr_hit) {
- if (!mf->write) {
- dq_push(p_L2c->L2todramqueue, mf);
+ if (!mf->m_write) {
+ L2todramqueue->push(mf,gpu_sim_cycle);
} else {
// if request is writeback from L1 and misses,
// then redirect mf writes to dram (no write allocate)
mf->nbytes_L2 = mf->nbytes_L1 - READ_PACKET_SIZE;
- dq_push(p_L2c->L2todramqueue, mf);
+ L2todramqueue->push(mf,gpu_sim_cycle);
}
}
- if (mf->mshr) mshr_update_status(mf->mshr, IN_L2TODRAMQUEUE);
- p_L2c->L2request = NULL;
+ if (mf->mshr) mf->mshr->set_status(IN_L2TODRAMQUEUE);
+ L2request = NULL;
}
}
}
@@ -564,188 +473,135 @@ void L2c_service_mem_req ( dram_t* dram_p, int dm_id )
}
// service memory request in L2todramqueue, pushing to dram
-void L2c_push_miss_to_dram ( dram_t* dram_p )
+void memory_partition_unit::L2c_push_miss_to_dram()
{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- mem_fetch_t* mf;
+ if ( m_config->gpgpu_dram_sched_queue_size && m_dram->full() )
+ return;
- if ( gpgpu_dram_sched_queue_size && dram_full(dram_p) ) return;
-
- mf = (mem_fetch_t*) dq_pop(p_L2c->L2todram_wbqueue); //prioritize writeback
- if (!mf) mf = (mem_fetch_t*) dq_pop(p_L2c->L2todramqueue);
+ mem_fetch* mf = L2todram_wbqueue->pop(gpu_sim_cycle); //prioritize writeback
+ if (!mf) mf = L2todramqueue->pop(gpu_sim_cycle);
if (mf) {
- if (mf->write) {
- L2_write_miss++;
+ if (mf->m_write) {
+ m_stats->L2_write_miss++;
} else {
- L2_read_miss++;
+ m_stats->L2_read_miss++;
}
- p_L2c->m_missTracker->new_miss(mf);
- memlatstat_dram_access(mf, dram_p->id, mf->tlx.bk);
- dram_push(dram_p,
- mf->tlx.bk, mf->tlx.row, mf->tlx.col,
- mf->nbytes_L2, mf->write,
- mf->wid, mf->sid, mf->cache_hits_waiting, mf->addr, mf);
- if (mf->mshr) mshr_update_status(mf->mshr, IN_DRAM_REQ_QUEUE);
+ m_missTracker->new_miss(mf);
+ m_dram->push(mf);
+ if (mf->mshr) mf->mshr->set_status(IN_DRAM_REQ_QUEUE);
}
}
-//Service writes that are finished in Dram
-//only updates the stats and frees the mf
-void dramtoL2_service_write(mem_fetch_t * mf) {
- freed_L2write_mfs++;
- free(mf);
- gpgpu_n_processed_writes++;
-}
-
// pop completed memory request from dram and push it to dram-to-L2 queue
-void L2c_get_dram_output ( dram_t* dram_p )
+void memory_partition_unit::L2c_get_dram_output ()
{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- mem_fetch_t* mf;
- mem_fetch_t* mf_top;
- if ( dq_full(p_L2c->dramtoL2queue) || dq_full(p_L2c->dramtoL2writequeue) ) return;
- mf_top = (mem_fetch_t*) dram_top(dram_p); //test
- mf = (mem_fetch_t*) dram_pop(dram_p);
+ mem_fetch* mf;
+ mem_fetch* mf_top;
+ if ( dramtoL2queue->full() || dramtoL2writequeue->full() ) return;
+ mf_top = m_dram->top();
+ mf = m_dram->pop();
assert (mf_top==mf );
if (mf) {
- if (gpgpu_l2_readoverwrite && mf->write)
- dq_push(p_L2c->dramtoL2writequeue, mf);
+ if (m_config->gpgpu_l2_readoverwrite && mf->m_write)
+ dramtoL2writequeue->push(mf,gpu_sim_cycle);
else
- dq_push(p_L2c->dramtoL2queue, mf);
- if (mf->mshr) mshr_update_status(mf->mshr, IN_DRAMTOL2QUEUE);
+ dramtoL2queue->push(mf,gpu_sim_cycle);
+ if (mf->mshr) mf->mshr->set_status(IN_DRAMTOL2QUEUE);
}
}
// service memory request in dramtoL2queue, writing to L2 as necessary
// (may cause cache eviction and subsequent writeback)
-void L2c_process_dram_output ( dram_t* dram_p, int dm_id )
+void memory_partition_unit::L2c_process_dram_output()
{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- static mem_fetch_t **L2dramout = NULL;
- static unsigned long long int *wb_addr = NULL;
- if (!L2dramout) L2dramout = (mem_fetch_t**)calloc(gpu_n_mem, sizeof(mem_fetch_t*));
- if (!wb_addr) {
- wb_addr = (unsigned long long int*)calloc(gpu_n_mem, sizeof(unsigned long long int));
- for (unsigned i = 0; i < gpu_n_mem; i++) wb_addr[i] = -1;
- }
-
- if (L2dramout[dm_id] == NULL) {
+ if (L2dramout == NULL) {
// pop from mshr chain if it is not empty, otherwise, pop a new cacheline from dram output queue
- if (p_L2c->m_mshr->mshr_chain_empty() == false) {
- L2dramout[dm_id] = p_L2c->m_mshr->mshr_chain_top();
- p_L2c->m_mshr->mshr_chain_pop();
+ if (m_mshr->mshr_chain_empty() == false) {
+ L2dramout = m_mshr->mshr_chain_top();
+ m_mshr->mshr_chain_pop();
} else {
- L2dramout[dm_id] = (mem_fetch_t*) dq_pop(p_L2c->dramtoL2queue);
- if (!L2dramout[dm_id]) L2dramout[dm_id] = (mem_fetch_t*) dq_pop(p_L2c->dramtoL2writequeue);
+ L2dramout = dramtoL2queue->pop(gpu_sim_cycle);
+ if (!L2dramout) L2dramout = dramtoL2writequeue->pop(gpu_sim_cycle);
- if (L2dramout[dm_id] != NULL) {
- p_L2c->m_mshr->miss_serviced(L2dramout[dm_id]);
+ if (L2dramout != NULL) {
+ m_mshr->miss_serviced(L2dramout);
- if (p_L2c->m_mshr->mshr_chain_empty() == false) { // possible if this is a L2 writeback
- L2dramout[dm_id] = p_L2c->m_mshr->mshr_chain_top();
- p_L2c->m_mshr->mshr_chain_pop();
+ if (m_mshr->mshr_chain_empty() == false) { // possible if this is a L2 writeback
+ L2dramout = m_mshr->mshr_chain_top();
+ m_mshr->mshr_chain_pop();
}
}
}
}
- mem_fetch_t* mf = L2dramout[dm_id];
+ mem_fetch* mf = L2dramout;
if (mf) {
- if (!mf->write) { //service L2 read miss
+ if (!mf->m_write) { //service L2 read miss
// it is a pre-fill dramout mf
- if (wb_addr[dm_id] == (unsigned long long int)-1) {
- if ( dq_full(p_L2c->L2tocbqueue) ) goto RETURN;
+ if (wb_addr == (unsigned long long int)-1) {
+ if ( L2tocbqueue->full() ) goto RETURN;
- if (mf->mshr) mshr_update_status(mf->mshr, IN_L2TOCBQUEUE_MISS);
+ if (mf->mshr) mf->mshr->set_status(IN_L2TOCBQUEUE_MISS);
//only transfer across icnt once the whole line has been received by L2 cache
mf->type = REPLY_DATA;
- dq_push(p_L2c->L2tocbqueue, mf);
+ L2tocbqueue->push(mf,gpu_sim_cycle);
- assert(mf->sid <= (int)gpu_n_shader);
- shd_cache_line_t *fetch_line_exist = shd_cache_probe(p_L2c->L2cache, mf->addr);
+ shd_cache_line_t *fetch_line_exist = shd_cache_probe(L2cache, mf->addr);
if (fetch_line_exist == NULL) {
- wb_addr[dm_id] = L2_shd_cache_fill(p_L2c->L2cache, mf->addr, gpu_sim_cycle );
+ wb_addr = L2_shd_cache_fill(L2cache, mf->addr, gpu_sim_cycle );
}
}
// only perform a write on cache eviction (write-back policy)
// it is the 1st or nth time trial to writeback
- if (wb_addr[dm_id] != (unsigned long long int)-1) {
+ if (wb_addr != (unsigned long long int)-1) {
// performing L2 writeback (no false sharing for memory-side cache)
- int wb_succeed = L2c_write_back(wb_addr[dm_id], p_L2c->L2cache->line_sz, dm_id );
+ int wb_succeed = L2c_write_back(wb_addr, L2cache->line_sz);
if (!wb_succeed) goto RETURN; //try again next cycle
}
- p_L2c->m_missTracker->miss_serviced(mf);
- L2dramout[dm_id] = NULL;
- wb_addr[dm_id] = -1;
+ m_missTracker->miss_serviced(mf);
+ L2dramout = NULL;
+ wb_addr = -1;
} else { //service L2 write miss
- p_L2c->m_missTracker->miss_serviced(mf);
- dramtoL2_service_write(mf);
- L2dramout[dm_id] = NULL;
- wb_addr[dm_id] = -1;
+ m_missTracker->miss_serviced(mf);
+ freed_L2write_mfs++;
+ free(mf);
+ gpgpu_n_processed_writes++;
+ L2dramout = NULL;
+ wb_addr = -1;
}
}
RETURN:
- assert (L2dramout[dm_id] || wb_addr[dm_id] == (unsigned long long int)-1);
+ assert (L2dramout || wb_addr == (unsigned long long int)-1);
}
// Writeback from L2 to DRAM:
// - Takes in memory address and their parameters and pushes to dram request queue
// - This is used only for L2 writeback
-unsigned char L2c_write_back(unsigned long long int addr, int bsize, int dram_id )
+bool memory_partition_unit::L2c_write_back( unsigned long long int addr, int bsize )
{
- addrdec_t tlx;
- addrdec_tlx(addr,&tlx);
-
- assert(dram[dram_id]->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[dram_id]->m_L2cache);
-
- if ( dq_full(p_L2c->L2todram_wbqueue) ) return 0;
-
- mem_fetch_t *mf;
-
- mf = (mem_fetch_t*) malloc(sizeof(mem_fetch_t));
+ if ( L2todram_wbqueue->full() )
+ return false;
+ mem_fetch *mf = new mem_fetch(addr,
+ bsize+READ_PACKET_SIZE/*l1*/,
+ bsize/*l2*/,
+ 0/*sid*/,0/*tpc*/,0/*wid*/,0/*cache_hits_waiting*/,NULL,true,
+ partial_write_mask_t(),
+ L2_WRBK_ACC,
+ L2_WTBK_DATA,
+ -1/*pc*/);
+ m_stats->memlatstat_start(mf);
made_write_mfs++;
- mf->request_uid = g_next_mf_request_uid++;
- mf->addr = addr;
- mf->nbytes_L1 = bsize + READ_PACKET_SIZE;
- mf->txbytes_L1 = 0;
- mf->rxbytes_L1 = 0;
- mf->nbytes_L2 = bsize;
- mf->sid = gpu_n_shader; // (gpu_n_shader+1);
- mf->wid = 0;
- mf->txbytes_L2 = 0;
- mf->rxbytes_L2 = 0;
- mf->mshr = NULL;
- mf->pc = -1; // disable ptx_file_line_stats
- mf->write = 1; // it is writeback
- mf->mem_acc = L2_WRBK_ACC;
- memlatstat_start(mf);
- mf->tlx = tlx;
- mf->bank = mf->tlx.bk;
- mf->chip = mf->tlx.chip;
-
-
- //writeback
- mf->type = L2_WTBK_DATA;
- if (!dq_push(p_L2c->L2todram_wbqueue, mf)) assert(0);
+ L2todram_wbqueue->push(mf,gpu_sim_cycle);
gpgpu_n_sent_writes++;
- return 1;
+ return true;
}
-unsigned int L2c_cache_flush ( dram_t* dram_p) {
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- shd_cache_t *cp = p_L2c->L2cache;
+unsigned int memory_partition_unit::L2c_cache_flush()
+{
+ shd_cache_t *cp = L2cache;
int dirty_lines_flushed = 0 ;
for (unsigned i = 0; i < cp->nset * cp->assoc ; i++) {
if ( (cp->lines[i].status & (DIRTY|VALID)) == (DIRTY|VALID) ) {
@@ -757,158 +613,141 @@ unsigned int L2c_cache_flush ( dram_t* dram_p) {
return dirty_lines_flushed;
}
-void L2c_init_stat()
+void memory_partition_unit::L2c_print_cache_stat(unsigned &accesses, unsigned &misses) const
{
- L2_cbtoL2length = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int));
- L2_cbtoL2writelength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int));
- L2_L2tocblength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int));
- L2_dramtoL2length = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int));
- L2_dramtoL2writelength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int));
- L2_L2todramlength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int));
+ FILE *fp = stdout;
+ shd_cache_print(L2cache,fp,accesses,misses);
+ m_mshr->print_stat(fp);
+ m_missTracker->print_stat(fp);
+ m_accessLocality->print_stat(fp, false);
}
-void L2c_update_stat( dram_t* dram_p)
+void memory_partition_unit::L2c_update_stat()
{
- assert(dram_p->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache);
-
- int i = dram_p->id;
-
- if (p_L2c->cbtoL2queue->length > L2_cbtoL2length[i])
- L2_cbtoL2length[i] = p_L2c->cbtoL2queue->length;
- if (p_L2c->cbtoL2writequeue->length > L2_cbtoL2writelength[i])
- L2_cbtoL2writelength[i] = p_L2c->cbtoL2writequeue->length;
- if (p_L2c->L2tocbqueue->length > L2_L2tocblength[i])
- L2_L2tocblength[i] = p_L2c->L2tocbqueue->length;
- if (p_L2c->dramtoL2queue->length > L2_dramtoL2length[i])
- L2_dramtoL2length[i] = p_L2c->dramtoL2queue->length;
- if (p_L2c->dramtoL2writequeue->length > L2_dramtoL2writelength[i])
- L2_dramtoL2writelength[i] = p_L2c->dramtoL2writequeue->length;
- if (p_L2c->L2todramqueue->length > L2_L2todramlength[i])
- L2_L2todramlength[i] = p_L2c->L2todramqueue->length;
+ unsigned i=m_id;
+ if (cbtoL2queue->get_length() > m_stats->L2_cbtoL2length[i])
+ m_stats->L2_cbtoL2length[i] = cbtoL2queue->get_length();
+ if (cbtoL2writequeue->get_length() > m_stats->L2_cbtoL2writelength[i])
+ m_stats->L2_cbtoL2writelength[i] = cbtoL2writequeue->get_length();
+ if (L2tocbqueue->get_length() > m_stats->L2_L2tocblength[i])
+ m_stats->L2_L2tocblength[i] = L2tocbqueue->get_length();
+ if (dramtoL2queue->get_length() > m_stats->L2_dramtoL2length[i])
+ m_stats->L2_dramtoL2length[i] = dramtoL2queue->get_length();
+ if (dramtoL2writequeue->get_length() > m_stats->L2_dramtoL2writelength[i])
+ m_stats->L2_dramtoL2writelength[i] = dramtoL2writequeue->get_length();
+ if (L2todramqueue->get_length() > m_stats->L2_L2todramlength[i])
+ m_stats->L2_L2todramlength[i] = L2todramqueue->get_length();
}
-void L2c_print_stat( )
+void memory_stats_t::L2c_print_stat( unsigned n_mem )
{
unsigned i;
printf(" ");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<n_mem;i++) {
printf(" dram[%d]", i);
}
printf("\n");
printf("cbtoL2 queue maximum length =");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<n_mem;i++) {
printf("%8d", L2_cbtoL2length[i]);
}
printf("\n");
printf("cbtoL2 write queue maximum length =");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<n_mem;i++) {
printf("%8d", L2_cbtoL2writelength[i]);
}
printf("\n");
printf("L2tocb queue maximum length =");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<n_mem;i++) {
printf("%8d", L2_L2tocblength[i]);
}
printf("\n");
printf("dramtoL2 queue maximum length =");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<n_mem;i++) {
printf("%8d", L2_dramtoL2length[i]);
}
printf("\n");
printf("dramtoL2 write queue maximum length =");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<n_mem;i++) {
printf("%8d", L2_dramtoL2writelength[i]);
}
printf("\n");
printf("L2todram queue maximum length =");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<n_mem;i++) {
printf("%8d", L2_L2todramlength[i]);
}
printf("\n");
}
-void L2c_print_cache_stat()
+void memory_stats_t::print( FILE *fp )
{
- unsigned i;
- int j, k;
- for (i=0,j=0,k=0;i<gpu_n_mem;i++) {
- assert(dram[i]->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
+ fprintf(fp,"L2_write_miss = %d\n", L2_write_miss);
+ fprintf(fp,"L2_write_hit = %d\n", L2_write_hit);
+ fprintf(fp,"L2_read_miss = %d\n", L2_read_miss);
+ fprintf(fp,"L2_read_hit = %d\n", L2_read_hit);
+}
- shd_cache_print(p_L2c->L2cache,stdout);
- j += p_L2c->L2cache->miss;
- k += p_L2c->L2cache->access;
- p_L2c->m_mshr->print_stat(stdout);
- p_L2c->m_missTracker->print_stat(stdout);
- p_L2c->m_accessLocality->print_stat(stdout, false);
- }
+void gpgpu_sim::L2c_print_cache_stat() const
+{
+ unsigned i, j, k;
+ for (i=0,j=0,k=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->L2c_print_cache_stat(k,j);
printf("L2 Cache Total Miss Rate = %0.3f\n", (float)j/k);
}
-void L2c_print_debug( )
+void gpgpu_sim::L2c_print_debug()
{
unsigned i;
printf(" ");
- for (i=0;i<gpu_n_mem;i++) {
+ for (i=0;i<m_n_mem;i++)
printf(" dram[%d]", i);
- }
printf("\n");
printf("cbtoL2 queue length =");
- for (i=0;i<gpu_n_mem;i++) {
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
- printf("%8d", p_L2c->cbtoL2queue->length);
- }
+ for (i=0;i<m_n_mem;i++)
+ printf("%8d", m_memory_partition_unit[i]->get_cbtoL2queue_length() );
printf("\n");
printf("cbtoL2 write queue length =");
- for (i=0;i<gpu_n_mem;i++) {
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
- printf("%8d", p_L2c->cbtoL2writequeue->length);
- }
+ for (i=0;i<m_n_mem;i++)
+ printf("%8d", m_memory_partition_unit[i]->get_cbtoL2writequeue_length());
printf("\n");
printf("L2tocb queue length =");
- for (i=0;i<gpu_n_mem;i++) {
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
- printf("%8d", p_L2c->L2tocbqueue->length);
+ for (i=0;i<m_n_mem;i++) {
+ printf("%8d", m_memory_partition_unit[i]->get_L2tocbqueue_length());
}
printf("\n");
printf("dramtoL2 queue length =");
- for (i=0;i<gpu_n_mem;i++) {
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
- printf("%8d", p_L2c->dramtoL2queue->length);
+ for (i=0;i<m_n_mem;i++) {
+ printf("%8d", m_memory_partition_unit[i]->get_dramtoL2queue_length());
}
printf("\n");
printf("dramtoL2 write queue length =");
- for (i=0;i<gpu_n_mem;i++) {
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
- printf("%8d", p_L2c->dramtoL2writequeue->length);
+ for (i=0;i<m_n_mem;i++) {
+ printf("%8d", m_memory_partition_unit[i]->get_dramtoL2writequeue_length());
}
printf("\n");
printf("L2todram queue length =");
- for (i=0;i<gpu_n_mem;i++) {
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
- printf("%8d", p_L2c->L2todramqueue->length);
+ for (i=0;i<m_n_mem;i++) {
+ printf("%8d", m_memory_partition_unit[i]->get_L2todramqueue_length());
}
printf("\n");
printf("L2todram writeback queue length =");
- for (i=0;i<gpu_n_mem;i++) {
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
- printf("%8d", p_L2c->L2todram_wbqueue->length);
+ for (i=0;i<m_n_mem;i++) {
+ printf("%8d", m_memory_partition_unit[i]->get_L2todram_wbqueue_length());
}
printf("\n");
}
@@ -917,78 +756,55 @@ void L2c_print_debug( )
#define SAMPLELOG 222
#define DUMPLOG 333
-void L2c_log(int task)
+void memory_partition_unit::L2c_log(int task)
{
- unsigned i;
- static void ** cbtol2_Dist ;
- static void ** cbtoL2wr_Dist ;
- static void ** L2tocb_Dist ;
- static void ** dramtoL2_Dist ;
- static void ** dramtoL2wr_Dist ;
- static void ** L2todram_Dist ;
- static void ** L2todram_wb_Dist ;
- if (task == CREATELOG) {
- cbtol2_Dist = (void **) calloc(gpu_n_mem,sizeof(void*));
- cbtoL2wr_Dist = (void **) calloc(gpu_n_mem,sizeof(void*));
- L2tocb_Dist = (void **) calloc(gpu_n_mem,sizeof(void*));
- dramtoL2_Dist = (void **)calloc(gpu_n_mem,sizeof(void*));
- dramtoL2wr_Dist = (void **)calloc(gpu_n_mem,sizeof(void*));
- L2todram_Dist = (void **)calloc(gpu_n_mem,sizeof(void*));
- L2todram_wb_Dist = (void **)calloc(gpu_n_mem,sizeof(void*));
-
- for (i=0;i<gpu_n_mem;i++) {
- assert(dram[i]->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
-
- cbtol2_Dist[i] = StatCreate("cbtoL2",1,p_L2c->cbtoL2queue->max_len);
- cbtoL2wr_Dist[i] = StatCreate("cbtoL2write",1,p_L2c->cbtoL2writequeue->max_len);
- L2tocb_Dist[i] = StatCreate("L2tocb",1,p_L2c->L2tocbqueue->max_len);
- dramtoL2_Dist[i] = StatCreate("dramtoL2",1,p_L2c->dramtoL2queue->max_len);
- dramtoL2wr_Dist[i] = StatCreate("dramtoL2write",1,p_L2c->dramtoL2writequeue->max_len);
- L2todram_Dist[i] = StatCreate("L2todram",1,p_L2c->L2todramqueue->max_len);
- L2todram_wb_Dist[i] = StatCreate("L2todram_wb",1,p_L2c->L2todram_wbqueue->max_len);
- }
- } else if (task == SAMPLELOG) {
- for (i=0;i<gpu_n_mem;i++) {
- assert(dram[i]->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
-
- StatAddSample(cbtol2_Dist[i], p_L2c->cbtoL2queue->length);
- StatAddSample(cbtoL2wr_Dist[i], p_L2c->cbtoL2writequeue->length);
- StatAddSample(L2tocb_Dist[i], p_L2c->L2tocbqueue->length);
- StatAddSample(dramtoL2_Dist[i], p_L2c->dramtoL2queue->length);
- StatAddSample(dramtoL2wr_Dist[i], p_L2c->dramtoL2writequeue->length);
- StatAddSample(L2todram_Dist[i], p_L2c->L2todramqueue->length);
- StatAddSample(L2todram_wb_Dist[i], p_L2c->L2todram_wbqueue->length);
- }
+ if (task == SAMPLELOG) {
+ StatAddSample(cbtol2_Dist, cbtoL2queue->get_length());
+ StatAddSample(cbtoL2wr_Dist, cbtoL2writequeue->get_length());
+ StatAddSample(L2tocb_Dist, L2tocbqueue->get_length());
+ StatAddSample(dramtoL2_Dist, dramtoL2queue->get_length());
+ StatAddSample(dramtoL2wr_Dist, dramtoL2writequeue->get_length());
+ StatAddSample(L2todram_Dist, L2todramqueue->get_length());
+ StatAddSample(L2todram_wb_Dist, L2todram_wbqueue->get_length());
} else if (task == DUMPLOG) {
- for (i=0;i<gpu_n_mem;i++) {
- printf ("Queue Length DRAM[%d] ",i); StatDisp(cbtol2_Dist[i]);
- printf ("Queue Length DRAM[%d] ",i); StatDisp(cbtoL2wr_Dist[i]);
- printf ("Queue Length DRAM[%d] ",i); StatDisp(L2tocb_Dist[i]);
- printf ("Queue Length DRAM[%d] ",i); StatDisp(dramtoL2_Dist[i]);
- printf ("Queue Length DRAM[%d] ",i); StatDisp(dramtoL2wr_Dist[i]);
- printf ("Queue Length DRAM[%d] ",i); StatDisp(L2todram_Dist[i]);
- printf ("Queue Length DRAM[%d] ",i); StatDisp(L2todram_wb_Dist[i]);
- }
+ printf ("Queue Length DRAM[%d] ",m_id); StatDisp(cbtol2_Dist);
+ printf ("Queue Length DRAM[%d] ",m_id); StatDisp(cbtoL2wr_Dist);
+ printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2tocb_Dist);
+ printf ("Queue Length DRAM[%d] ",m_id); StatDisp(dramtoL2_Dist);
+ printf ("Queue Length DRAM[%d] ",m_id); StatDisp(dramtoL2wr_Dist);
+ printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2todram_Dist);
+ printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2todram_wb_Dist);
}
}
-void L2c_latency_log_dump()
+void gpgpu_sim::L2c_latency_log_dump()
{
- unsigned i;
- for (i=0;i<gpu_n_mem;i++) {
- assert(dram[i]->m_L2cache != NULL);
- L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache);
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->L2c_latency_log_dump();
+}
- printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->cbtoL2queue->lat_stat);
- printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->cbtoL2writequeue->lat_stat);
- printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->L2tocbqueue->lat_stat);
- printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->dramtoL2queue->lat_stat);
- printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->dramtoL2writequeue->lat_stat);
- printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->L2todramqueue->lat_stat);
- printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->L2todram_wbqueue->lat_stat);
- }
+void memory_partition_unit::L2c_latency_log_dump()
+{
+ printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(cbtoL2queue->get_lat_stat());
+ printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(cbtoL2writequeue->get_lat_stat());
+ printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2tocbqueue->get_lat_stat());
+ printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(dramtoL2queue->get_lat_stat());
+ printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(dramtoL2writequeue->get_lat_stat());
+ printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2todramqueue->get_lat_stat());
+ printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2todram_wbqueue->get_lat_stat());
+}
+
+bool memory_partition_unit::busy() const
+{
+ return !m_request_tracker.empty();
}
+void memory_partition_unit::request_tracker_insert(class mem_fetch *mf)
+{
+ m_request_tracker.insert(mf);
+}
+void memory_partition_unit::request_tracker_erase(class mem_fetch *mf)
+{
+ m_request_tracker.erase(mf);
+}
diff --git a/src/gpgpu-sim/l2cache.h b/src/gpgpu-sim/l2cache.h
index 6566dd7..55202ee 100644
--- a/src/gpgpu-sim/l2cache.h
+++ b/src/gpgpu-sim/l2cache.h
@@ -1,53 +1,278 @@
-#pragma once
+/*
+ * l2cache.h
+ *
+ * Copyright (c) 2009 by Tor M. Aamodt and
+ * 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 MC_PARTITION_INCLUDED
+#define MC_PARTITION_INCLUDED
#include "dram.h"
+#include "../tr1_hash_map.h"
+#include "../abstract_hardware_model.h"
+
+#include <list>
+#include <queue>
+
+class mem_fetch;
+
+class L2c_mshr
+{
+private:
+ typedef std::list<const mem_fetch*> mem_fetch_list;
+ typedef tr1_hash_map<address_type, mem_fetch_list> L2missGroup;
+ L2missGroup m_L2missgroup; // structure tracking redundant dram access
+
+ struct active_chain {
+ address_type cacheTag;
+ mem_fetch_list *list;
+ active_chain() : cacheTag(0xDEADBEEF), list(NULL) { }
+ };
+ active_chain m_active_mshr_chain;
+ size_t m_linesize; // L2 cache line size
+
+ const size_t m_n_entries; // total number of entries available
+ size_t m_entries_used; // number of entries in use
+
+ int m_n_miss;
+ int m_n_miss_serviced_by_dram;
+ int m_n_mshr_hits;
+ size_t m_max_entries_used;
+
+ address_type cache_tag(const mem_fetch *mf) const;
+
+public:
+ L2c_mshr(size_t linesize, size_t n_entries = 64)
+ : m_linesize(linesize), m_n_entries(n_entries), m_entries_used(0),
+ m_n_miss(0), m_n_miss_serviced_by_dram(0), m_n_mshr_hits(0), m_max_entries_used(0) { }
+
+ // add a cache miss to MSHR, return true if this access is hit another existing entry and merges with it
+ bool new_miss(const mem_fetch *mf);
+
+ // notify MSHR that a new cache line has been fetched, activate the associated MSHR chain
+ void miss_serviced(const mem_fetch *mf);
+
+ // probe if there are pending hits left in this MSHR chain
+ bool mshr_chain_empty();
+
+ // peek the first entry in the active MSHR chain
+ mem_fetch *mshr_chain_top();
+
+ // pop the first entry in the active MSHR chain
+ void mshr_chain_pop();
+
+ void print(FILE *fout = stdout);
+ void print_stat(FILE *fout = stdout) const;
+};
+
+class L2c_miss_tracker
+{
+private:
+ typedef std::set<mem_fetch*> mem_fetch_set;
+ typedef tr1_hash_map<address_type, mem_fetch_set> L2missGroup;
+ L2missGroup m_L2missgroup; // structure tracking redundant dram access
+ size_t m_linesize; // L2 cache line size
+
+ typedef tr1_hash_map<address_type, int> L2redundantCnt;
+ L2redundantCnt m_L2redundantCnt;
+
+ int m_totalL2redundantAcc;
+
+ address_type cache_tag(const mem_fetch *mf) const;
+
+public:
+ L2c_miss_tracker(size_t linesize) : m_linesize(linesize), m_totalL2redundantAcc(0) { }
+ void new_miss(mem_fetch *mf);
+ void miss_serviced(mem_fetch *mf);
+
+ void print(FILE *fout, bool brief = true);
+ void print_stat(FILE *fout, bool brief = true) const;
+};
+
+class L2c_access_locality
+{
+public:
+ L2c_access_locality(size_t linesize) : m_linesize(linesize), m_totalL2accAcc(0) { }
+ void print_stat(FILE *fout, bool brief = true) const;
+ void access(mem_fetch *mf);
+private:
+ address_type cache_tag(const mem_fetch *mf) const;
+
+ size_t m_linesize; // L2 cache line size
+
+ typedef tr1_hash_map<address_type, int> L2accCnt;
+ L2accCnt m_L2accCnt;
+ int m_totalL2accAcc;
+};
+
+class memory_partition_unit
+{
+public:
+ memory_partition_unit( unsigned partition_id, struct memory_config *config);
+ ~memory_partition_unit();
+
+ void set_stats( class memory_stats_t *stats );
+
+ void cache_cycle();
+
+ bool has_cache() { return L2cache != NULL; }
+ unsigned L2c_get_linesize();
+ bool full() const;
+ bool busy() const;
+
+ void push( class mem_fetch* mf, unsigned long long clock_cycle );
+ class mem_fetch* pop();
+ class mem_fetch* top();
+ void issueCMD();
+ void visualizer_print( gzFile visualizer_file );
+ void L2c_latency_log_dump();
+ void L2c_log(int task);
+ unsigned L2c_cache_flush();
+ void L2c_print_cache_stat(unsigned &accesses, unsigned &misses) const;
+
+ unsigned get_cbtoL2queue_length() const { return cbtoL2queue->get_length(); }
+ unsigned get_cbtoL2writequeue_length() const { return cbtoL2writequeue->get_length(); }
+ unsigned get_dramtoL2queue_length() const { return dramtoL2queue->get_length(); }
+ unsigned get_dramtoL2writequeue_length() const { return dramtoL2writequeue->get_length(); }
+ unsigned get_L2todramqueue_length() const { return L2todramqueue->get_length(); }
+ unsigned get_L2todram_wbqueue_length() const { return L2todram_wbqueue->get_length(); }
+ unsigned get_L2tocbqueue_length() const { return L2tocbqueue->get_length(); }
+
+ void print_stat( FILE *fp ) { m_dram->print_stat(fp); }
+ void visualize() const { m_dram->visualize(); }
+ unsigned dram_que_length() const { return m_dram->que_length(); }
+ void queue_latency_log_dump( FILE *fp ) { m_dram->queue_latency_log_dump(fp); }
+ void print( FILE *fp ) { m_dram->print(fp); }
-// L2 Cache Creation
-void L2c_create ( dram_t* dram_p, const char* cache_opt );
+private:
+ void request_tracker_insert(class mem_fetch *mf);
+ void request_tracker_erase(class mem_fetch *mf);
-void L2c_qlen ( dram_t *dram_p );
+ // pop completed memory request from dram and push it to dram-to-L2 queue
+ void L2c_get_dram_output();
-// service memory request in icnt-to-L2 queue, writing to L2 as necessary
-// (if L2 writeback miss, writeback to memory)
-void L2c_service_mem_req ( dram_t* dram_p, int dm_id );
+ // service memory request in icnt-to-L2 queue, writing to L2 as necessary
+ // (if L2 writeback miss, writeback to memory)
+ void L2c_service_mem_req();
+
+ // service memory request in L2todramqueue, pushing to dram
+ void L2c_push_miss_to_dram();
+
+ // service memory request in dramtoL2queue, writing to L2 as necessary
+ // (may cause cache eviction and subsequent writeback)
+ void L2c_process_dram_output();
+
+ bool L2c_write_back( unsigned long long int addr, int bsize );
+
+ // probe L2 cache for fullness
+ struct mem_fetch* L2c_pop( dram_t *dram_p );
+
+ void L2c_init_stat(unsigned n_mem);
+ void L2c_update_stat();
+ void L2c_print_debug();
-// service memory request in L2todramqueue, pushing to dram
-void L2c_push_miss_to_dram ( dram_t* dram_p );
+// data
+ unsigned m_id;
+ struct memory_config *m_config;
+ class dram_t *m_dram;
+ struct shd_cache_t *L2cache;
-// pop completed memory request from dram and push it to dram-to-L2 queue
-void L2c_get_dram_output ( dram_t* dram_p );
+ // model delay of ROP units with a fixed latency
+ struct rop_delay_t
+ {
+ unsigned long long ready_cycle;
+ class mem_fetch* req;
+ };
+ std::queue<rop_delay_t> m_rop;
-// service memory request in dramtoL2queue, writing to L2 as necessary
-// (may cause cache eviction and subsequent writeback)
-void L2c_process_dram_output ( dram_t* dram_p, int dm_id );
+ // these are various FIFOs between units within a memory partition
+ fifo_pipeline<mem_fetch> *cbtoL2queue;
+ fifo_pipeline<mem_fetch> *cbtoL2writequeue;
+ fifo_pipeline<mem_fetch> *dramtoL2queue;
+ fifo_pipeline<mem_fetch> *dramtoL2writequeue;
+ fifo_pipeline<mem_fetch> *L2todramqueue;
+ fifo_pipeline<mem_fetch> *L2todram_wbqueue;
+ fifo_pipeline<mem_fetch> *L2tocbqueue;
-// Writeback from L2 to DRAM:
-// - Takes in memory address and their parameters and pushes to dram request queue
-// - This is used only for L2 writeback
-unsigned char L2c_write_back(unsigned long long int addr, int bsize, int dram_id );
+ mem_fetch *L2request; //request currently being serviced by the L2 Cache
-unsigned int L2c_cache_flush ( dram_t* dram_p);
+ L2c_mshr *m_mshr; // mshr model
+ L2c_miss_tracker *m_missTracker; // tracker observing for redundant misses
+ L2c_access_locality *m_accessLocality; // tracking true locality of L2 Cache access
-unsigned L2c_get_linesize( dram_t *dram_p );
+ class mem_fetch *L2dramout;
+ unsigned long long int wb_addr;
-// probe L2 cache for fullness
-int L2c_full( dram_t *dram_p );
-void L2c_push( dram_t *dram_p, struct mem_fetch *mf );
-struct mem_fetch* L2c_pop( dram_t *dram_p );
-struct mem_fetch* L2c_top( dram_t *dram_p );
+ class memory_stats_t *m_stats;
-void L2c_init_stat();
-void L2c_update_stat( dram_t* dram_p);
-void L2c_print_stat();
-void L2c_print_cache_stat();
-void L2c_print_debug();
-void L2c_log(int task);
-void L2c_latency_log_dump();
+ class Stats *cbtol2_Dist;
+ class Stats *cbtoL2wr_Dist;
+ class Stats *L2tocb_Dist;
+ class Stats *dramtoL2_Dist;
+ class Stats *dramtoL2wr_Dist;
+ class Stats *L2todram_Dist;
+ class Stats *L2todram_wb_Dist;
-void L2c_options(class OptionParser *opp);
+ std::set<mem_fetch*> m_request_tracker;
+};
-extern unsigned L2_write_miss;
-extern unsigned L2_write_hit;
-extern unsigned L2_read_hit;
-extern unsigned L2_read_miss;
-extern bool gpgpu_l2_readoverwrite;
+#endif
diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc
new file mode 100644
index 0000000..99a1e58
--- /dev/null
+++ b/src/gpgpu-sim/mem_fetch.cc
@@ -0,0 +1,106 @@
+/*
+ * mem_fetch.cc
+ *
+ * Copyright (c) 2009 by Tor M. Aamodt and
+ * 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 "mem_fetch.h"
+#include "mem_latency_stat.h"
+
+unsigned mem_fetch::sm_next_mf_request_uid=1;
+
+mem_fetch::mem_fetch( unsigned long long int addr,
+ int l1bsize,
+ int l2bsize,
+ int sid,
+ unsigned tpc,
+ int wid,
+ int cache_hits_waiting,
+ class mshr_entry * mshr,
+ bool write,
+ partial_write_mask_t partial_write_mask,
+ enum mem_access_type mem_acc,
+ enum mf_type type,
+ address_type pc )
+{
+ class mem_fetch *mf = this;
+ mf->request_uid = sm_next_mf_request_uid++;
+ mf->addr = addr;
+ mf->nbytes_L1 = l1bsize;
+ mf->nbytes_L2 = l2bsize;
+ mf->sid = sid;
+ mf->wid = wid;
+ mf->cache_hits_waiting = cache_hits_waiting;
+ mf->txbytes_L1 = 0;
+ mf->rxbytes_L1 = 0;
+ mf->mshr = mshr;
+ mf->m_write = write;
+ addrdec_tlx(addr,&mf->tlx);
+ mf->bank = mf->tlx.bk;
+ mf->chip = mf->tlx.chip;
+ mf->txbytes_L2 = 0;
+ mf->rxbytes_L2 = 0;
+ mf->write_mask = partial_write_mask;
+ mf->mem_acc = mem_acc;
+ mf->type = type;
+ mf->pc = pc;
+}
diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h
index 1db348a..7196690 100644
--- a/src/gpgpu-sim/mem_fetch.h
+++ b/src/gpgpu-sim/mem_fetch.h
@@ -67,9 +67,9 @@
#ifndef MEM_FETCH_H
#define MEM_FETCH_H
-#include "shader.h"
#include "addrdec.h"
#include "../abstract_hardware_model.h"
+#include <bitset>
enum mf_type {
RD_REQ = 0,
@@ -80,7 +80,38 @@ enum mf_type {
N_MF_TYPE
};
-typedef struct mem_fetch {
+enum mem_access_type {
+ GLOBAL_ACC_R = 0,
+ LOCAL_ACC_R = 1,
+ CONST_ACC_R = 2,
+ TEXTURE_ACC_R = 3,
+ GLOBAL_ACC_W = 4,
+ LOCAL_ACC_W = 5,
+ L2_WRBK_ACC = 6,
+ INST_ACC_R = 7,
+ NUM_MEM_ACCESS_TYPE = 8
+};
+
+const unsigned partial_write_mask_bits = 128; //must be at least size of largest memory access.
+typedef std::bitset<partial_write_mask_bits> partial_write_mask_t;
+
+class mem_fetch {
+public:
+ mem_fetch( unsigned long long int addr,
+ int l1bsize,
+ int l2bsize,
+ int sid,
+ unsigned tpc,
+ int wid,
+ int cache_hits_waiting,
+ class mshr_entry * mshr,
+ bool write,
+ partial_write_mask_t partial_write_mask,
+ enum mem_access_type mem_acc,
+ enum mf_type type,
+ address_type pc );
+
+public:
unsigned request_uid;
unsigned long long int addr;
int nbytes_L1;
@@ -92,9 +123,9 @@ typedef struct mem_fetch {
int sid; //shader core id
int wid; //warp id
int cache_hits_waiting;
- mshr_entry* mshr;
+ class mshr_entry* mshr;
address_type pc;
- unsigned char write;
+ bool m_write;
enum mem_access_type mem_acc;
unsigned int timestamp; //set to gpu_sim_cycle at struct creation
unsigned int timestamp2; //set to gpu_sim_cycle when pushed onto icnt to shader; only used for reads
@@ -104,8 +135,7 @@ typedef struct mem_fetch {
addrdec_t tlx;
enum mf_type type;
partial_write_mask_t write_mask;
- int source_node; //memory node id when sending from mem to shader
- //same as sid when sending from shader 2 mem
-} mem_fetch_t;
+ static unsigned sm_next_mf_request_uid;
+};
#endif
diff --git a/src/gpgpu-sim/mem_latency_stat.cc b/src/gpgpu-sim/mem_latency_stat.cc
index f225087..cd1a650 100644
--- a/src/gpgpu-sim/mem_latency_stat.cc
+++ b/src/gpgpu-sim/mem_latency_stat.cc
@@ -79,46 +79,14 @@
#include <stdlib.h>
#include <stdio.h>
-bool gpgpu_memlatency_stat;
-
-unsigned max_mrq_latency;
-unsigned max_dq_latency;
-unsigned max_mf_latency;
-unsigned max_icnt2mem_latency;
-unsigned max_icnt2sh_latency;
-unsigned mrq_lat_table[32];
-unsigned dq_lat_table[32];
-unsigned mf_lat_table[32];
-unsigned icnt2mem_lat_table[24];
-unsigned icnt2sh_lat_table[24];
-unsigned mf_lat_pw_table[32]; //table storing values of mf latency Per Window
-unsigned mf_num_lat_pw;
-unsigned mf_tot_lat_pw; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window
-unsigned long long int mf_total_lat;
-unsigned long long int ** mf_total_lat_table; //mf latency sums[dram chip id][bank id]
-unsigned ** mf_max_lat_table; //mf latency sums[dram chip id][bank id]
-unsigned num_mfs;
-unsigned int ***bankwrites; //bankwrites[shader id][dram chip id][bank id]
-unsigned int ***bankreads; //bankreads[shader id][dram chip id][bank id]
-unsigned int **totalbankwrites; //bankwrites[dram chip id][bank id]
-unsigned int **totalbankreads; //bankreads[dram chip id][bank id]
-unsigned int **totalbankaccesses; //bankaccesses[dram chip id][bank id]
-unsigned int *requests_by_warp;
-unsigned int *num_MCBs_accessed; //tracks how many memory controllers are accessed whenever any thread in a warp misses in cache
-unsigned int *position_of_mrq_chosen; //position of mrq in m_queue chosen
-unsigned *mf_num_lat_pw_perwarp;
-unsigned *mf_tot_lat_pw_perwarp; //total latency summed up per window per warp. divide by mf_num_lat_pw_perwarp to obtain average latency Per Window
-unsigned long long int *mf_total_lat_perwarp;
-unsigned *num_mfs_perwarp;
-unsigned *acc_mrq_length;
-
-unsigned ***mem_access_type_stats; // dram access type classification
-
-
-void memlatstat_init( )
+memory_stats_t::memory_stats_t( unsigned n_mem, unsigned n_shader, struct shader_core_config *shader_config, struct memory_config *mem_config )
{
unsigned i,j;
+ m_n_shader=n_shader;
+ m_n_mem=n_mem;
+ m_memory_config=mem_config;
+
max_mrq_latency = 0;
max_dq_latency = 0;
max_mf_latency = 0;
@@ -131,72 +99,85 @@ void memlatstat_init( )
memset(icnt2sh_lat_table, 0, sizeof(unsigned)*24);
memset(mf_lat_pw_table, 0, sizeof(unsigned)*32);
mf_num_lat_pw = 0;
- mf_num_lat_pw_perwarp = (unsigned *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int));
- mf_tot_lat_pw_perwarp = (unsigned *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int));
- mf_total_lat_perwarp = (unsigned long long int *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned long long int));
- num_mfs_perwarp = (unsigned *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int));
- acc_mrq_length = (unsigned *) calloc(gpu_n_mem, sizeof(unsigned int));
+ max_warps = n_shader * (shader_config->n_thread_per_shader / shader_config->warp_size+1);
+ mf_num_lat_pw_perwarp = (unsigned *) calloc(max_warps, sizeof(unsigned int));
+ mf_tot_lat_pw_perwarp = (unsigned *) calloc(max_warps, sizeof(unsigned int));
+ mf_total_lat_perwarp = (unsigned long long int *) calloc(max_warps, sizeof(unsigned long long int));
+ num_mfs_perwarp = (unsigned *) calloc(max_warps, sizeof(unsigned int));
+ acc_mrq_length = (unsigned *) calloc(n_mem, sizeof(unsigned int));
mf_tot_lat_pw = 0; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window
mf_total_lat = 0;
num_mfs = 0;
printf("*** Initializing Memory Statistics ***\n");
- requests_by_warp = (unsigned int*) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int));
- totalbankreads = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- totalbankwrites = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- totalbankaccesses = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- mf_total_lat_table = (unsigned long long int **) calloc(gpu_n_mem, sizeof(unsigned long long *));
- mf_max_lat_table = (unsigned **) calloc(gpu_n_mem, sizeof(unsigned *));
- bankreads = (unsigned int***) calloc(gpu_n_shader, sizeof(unsigned int**));
- bankwrites = (unsigned int***) calloc(gpu_n_shader, sizeof(unsigned int**));
- num_MCBs_accessed = (unsigned int*) calloc(gpu_n_mem*gpu_mem_n_bk, sizeof(unsigned int));
- if (gpgpu_dram_sched_queue_size) {
- position_of_mrq_chosen = (unsigned int*) calloc(gpgpu_dram_sched_queue_size, sizeof(unsigned int));
+ totalbankreads = (unsigned int**) calloc(n_mem, sizeof(unsigned int*));
+ totalbankwrites = (unsigned int**) calloc(n_mem, sizeof(unsigned int*));
+ totalbankaccesses = (unsigned int**) calloc(n_mem, sizeof(unsigned int*));
+ mf_total_lat_table = (unsigned long long int **) calloc(n_mem, sizeof(unsigned long long *));
+ mf_max_lat_table = (unsigned **) calloc(n_mem, sizeof(unsigned *));
+ bankreads = (unsigned int***) calloc(n_shader, sizeof(unsigned int**));
+ bankwrites = (unsigned int***) calloc(n_shader, sizeof(unsigned int**));
+ num_MCBs_accessed = (unsigned int*) calloc(n_mem*mem_config->gpu_mem_n_bk, sizeof(unsigned int));
+ if (mem_config->gpgpu_dram_sched_queue_size) {
+ position_of_mrq_chosen = (unsigned int*) calloc(mem_config->gpgpu_dram_sched_queue_size, sizeof(unsigned int));
} else
position_of_mrq_chosen = (unsigned int*) calloc(1024, sizeof(unsigned int));
- for (i=0;i<gpu_n_shader ;i++ ) {
- bankreads[i] = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- bankwrites[i] = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
- for (j=0;j<gpu_n_mem ;j++ ) {
- bankreads[i][j] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- bankwrites[i][j] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
+ for (i=0;i<n_shader ;i++ ) {
+ bankreads[i] = (unsigned int**) calloc(n_mem, sizeof(unsigned int*));
+ bankwrites[i] = (unsigned int**) calloc(n_mem, sizeof(unsigned int*));
+ for (j=0;j<n_mem ;j++ ) {
+ bankreads[i][j] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int));
+ bankwrites[i][j] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int));
}
}
- for (i=0;i<gpu_n_mem ;i++ ) {
- totalbankreads[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- totalbankwrites[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- totalbankaccesses[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
- mf_total_lat_table[i] = (unsigned long long int*) calloc(gpu_mem_n_bk, sizeof(unsigned long long int));
- mf_max_lat_table[i] = (unsigned *) calloc(gpu_mem_n_bk, sizeof(unsigned));
+ for (i=0;i<n_mem ;i++ ) {
+ totalbankreads[i] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int));
+ totalbankwrites[i] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int));
+ totalbankaccesses[i] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int));
+ mf_total_lat_table[i] = (unsigned long long int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned long long int));
+ mf_max_lat_table[i] = (unsigned *) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned));
}
mem_access_type_stats = (unsigned ***) malloc(NUM_MEM_ACCESS_TYPE * sizeof(unsigned **));
for (i = 0; i < NUM_MEM_ACCESS_TYPE; i++) {
int j;
- mem_access_type_stats[i] = (unsigned **) calloc(gpu_n_mem, sizeof(unsigned*));
- for (j=0; (unsigned) j< gpu_n_mem; j++) {
- mem_access_type_stats[i][j] = (unsigned *) calloc((gpu_mem_n_bk+1), sizeof(unsigned*));
+ mem_access_type_stats[i] = (unsigned **) calloc(n_mem, sizeof(unsigned*));
+ for (j=0; (unsigned) j< n_mem; j++) {
+ mem_access_type_stats[i][j] = (unsigned *) calloc((mem_config->gpu_mem_n_bk+1), sizeof(unsigned*));
}
}
+
+ L2_write_miss=0;
+ L2_write_hit=0;
+ L2_read_hit=0;
+ L2_read_miss=0;
+ L2_cbtoL2length = (unsigned int*) calloc(n_mem, sizeof(unsigned int));
+ L2_cbtoL2writelength = (unsigned int*) calloc(n_mem, sizeof(unsigned int));
+ L2_L2tocblength = (unsigned int*) calloc(n_mem, sizeof(unsigned int));
+ L2_dramtoL2length = (unsigned int*) calloc(n_mem, sizeof(unsigned int));
+ L2_dramtoL2writelength = (unsigned int*) calloc(n_mem, sizeof(unsigned int));
+ L2_L2todramlength = (unsigned int*) calloc(n_mem, sizeof(unsigned int));
}
-void memlatstat_start(mem_fetch_t *mf)
+void memory_stats_t::memlatstat_start(mem_fetch *mf)
{
mf->timestamp = gpu_sim_cycle + gpu_tot_sim_cycle;
mf->timestamp2 = 0;
}
// recorder the total latency
-unsigned memlatstat_done(mem_fetch_t *mf)
+unsigned memory_stats_t::memlatstat_done(mem_fetch *mf, unsigned n_warp_per_shader )
{
unsigned mf_latency;
- unsigned wid = mf->sid*gpu_n_warp_per_shader + mf->wid;
+ unsigned wid = mf->sid*n_warp_per_shader + mf->wid;
+ assert(wid<max_warps);
mf_latency = (gpu_sim_cycle+gpu_tot_sim_cycle) - mf->timestamp;
mf_num_lat_pw++;
mf_num_lat_pw_perwarp[wid]++;
mf_tot_lat_pw_perwarp[wid] += mf_latency;
mf_tot_lat_pw += mf_latency;
- check_time_vector_update(mf->mshr->insts[0].uid,MR_2SH_FQ_POP,mf_latency, mf->type ) ;
+ if( mf->mshr && mf->mshr->has_inst() )
+ check_time_vector_update(mf->mshr->get_insts_uid(),MR_2SH_FQ_POP,mf_latency,mf->type);
mf_lat_table[LOGB2(mf_latency)]++;
shader_mem_lat_log(mf->sid, mf_latency);
mf_total_lat_table[mf->chip][mf->bank] += mf_latency;
@@ -205,15 +186,15 @@ unsigned memlatstat_done(mem_fetch_t *mf)
return mf_latency;
}
-void memlatstat_icnt2sh_push(mem_fetch_t *mf)
+void memory_stats_t::memlatstat_icnt2sh_push(mem_fetch *mf)
{
mf->timestamp2 = gpu_sim_cycle+gpu_tot_sim_cycle;
}
-void memlatstat_read_done(mem_fetch_t *mf)
+void memory_stats_t::memlatstat_read_done(mem_fetch *mf, unsigned n_warp_per_shader)
{
- if (gpgpu_memlatency_stat) {
- unsigned mf_latency = memlatstat_done(mf);
+ if (m_memory_config->gpgpu_memlatency_stat) {
+ unsigned mf_latency = memlatstat_done(mf,n_warp_per_shader);
if (mf_latency > mf_max_lat_table[mf->chip][mf->bank]) {
mf_max_lat_table[mf->chip][mf->bank] = mf_latency;
@@ -227,13 +208,13 @@ void memlatstat_read_done(mem_fetch_t *mf)
}
}
-void memlatstat_dram_access(mem_fetch_t *mf, unsigned dram_id, unsigned bank)
+void memory_stats_t::memlatstat_dram_access(mem_fetch *mf)
{
- assert(dram_id < gpu_n_mem);
- assert(bank < gpu_mem_n_bk);
- if (gpgpu_memlatency_stat) {
- if (mf->write) {
- if ( (unsigned) mf->sid < gpu_n_shader ) { //do not count L2_writebacks here
+ unsigned dram_id = mf->chip;
+ unsigned bank = mf->bank;
+ if (m_memory_config->gpgpu_memlatency_stat) {
+ if (mf->m_write) {
+ if ( (unsigned) mf->sid < m_n_shader ) { //do not count L2_writebacks here
bankwrites[mf->sid][dram_id][bank]++;
shader_mem_acc_log( mf->sid, dram_id, bank, 'w');
}
@@ -243,18 +224,16 @@ void memlatstat_dram_access(mem_fetch_t *mf, unsigned dram_id, unsigned bank)
shader_mem_acc_log( mf->sid, dram_id, bank, 'r');
totalbankreads[dram_id][bank]++;
}
-
if (mf->pc != (unsigned) -1) {
ptx_file_line_stats_add_dram_traffic(mf->pc, 1);
}
-
mem_access_type_stats[mf->mem_acc][dram_id][bank]++;
}
}
-void memlatstat_icnt2mem_pop(mem_fetch_t *mf)
+void memory_stats_t::memlatstat_icnt2mem_pop(mem_fetch *mf)
{
- if (gpgpu_memlatency_stat) {
+ if (m_memory_config->gpgpu_memlatency_stat) {
unsigned icnt2mem_latency;
icnt2mem_latency = (gpu_tot_sim_cycle+gpu_sim_cycle) - mf->timestamp;
icnt2mem_lat_table[LOGB2(icnt2mem_latency)]++;
@@ -263,10 +242,10 @@ void memlatstat_icnt2mem_pop(mem_fetch_t *mf)
}
}
-void memlatstat_lat_pw( )
+void memory_stats_t::memlatstat_lat_pw( unsigned n_shader, unsigned n_thread_per_shader, unsigned warp_size )
{
unsigned i;
- if (mf_num_lat_pw && gpgpu_memlatency_stat) {
+ if (mf_num_lat_pw && m_memory_config->gpgpu_memlatency_stat) {
assert(mf_tot_lat_pw);
mf_total_lat = mf_tot_lat_pw;
num_mfs = mf_num_lat_pw;
@@ -274,12 +253,12 @@ void memlatstat_lat_pw( )
mf_tot_lat_pw = 0;
mf_num_lat_pw = 0;
}
- for (i=0;i < ((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1); i++) {
- if (mf_num_lat_pw_perwarp[i] && gpgpu_memlatency_stat) {
+ for (i=0;i < ((n_shader * n_thread_per_shader / warp_size)+1); i++) {
+ assert(i<max_warps);
+ if (mf_num_lat_pw_perwarp[i] && m_memory_config->gpgpu_memlatency_stat) {
assert(mf_tot_lat_pw_perwarp[i]);
mf_total_lat_perwarp[i] += mf_tot_lat_pw_perwarp[i];
num_mfs_perwarp[i] += mf_num_lat_pw_perwarp[i];
- //mf_lat_pw_table[LOGB2(mf_tot_lat_pw/mf_num_lat_pw)]++;
mf_tot_lat_pw_perwarp[i] = 0;
mf_num_lat_pw_perwarp[i] = 0;
}
@@ -287,12 +266,12 @@ void memlatstat_lat_pw( )
}
-void memlatstat_print( )
+void memory_stats_t::memlatstat_print( unsigned n_mem, unsigned gpu_mem_n_bk )
{
unsigned i,j,k,l,m;
unsigned max_bank_accesses, min_bank_accesses, max_chip_accesses, min_chip_accesses;
- if (gpgpu_memlatency_stat) {
+ if (m_memory_config->gpgpu_memlatency_stat) {
printf("maxmrqlatency = %d \n", max_mrq_latency);
printf("maxdqlatency = %d \n", max_dq_latency);
printf("maxmflatency = %d \n", max_mf_latency);
@@ -334,7 +313,7 @@ void memlatstat_print( )
/*MAXIMUM CONCURRENT ACCESSES TO SAME ROW*/
printf("maximum concurrent accesses to same row:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
printf("%9d ",max_conc_access2samerow[i][j]);
@@ -344,7 +323,7 @@ void memlatstat_print( )
/*MAXIMUM SERVICE TIME TO SAME ROW*/
printf("maximum service time to same row:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
printf("%9d ",max_servicetime2samerow[i][j]);
@@ -356,7 +335,7 @@ void memlatstat_print( )
int total_row_accesses = 0;
int total_num_activates = 0;
printf("average row accesses per activate:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
total_row_accesses += row_access[i][j];
@@ -375,7 +354,7 @@ void memlatstat_print( )
min_bank_accesses = 0xFFFFFFFF;
min_chip_accesses = 0xFFFFFFFF;
printf("number of total memory accesses made:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
l = totalbankaccesses[i][j];
@@ -413,7 +392,7 @@ void memlatstat_print( )
min_bank_accesses = 0xFFFFFFFF;
min_chip_accesses = 0xFFFFFFFF;
printf("number of total read accesses:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
l = totalbankreads[i][j];
@@ -451,7 +430,7 @@ void memlatstat_print( )
min_bank_accesses = 0xFFFFFFFF;
min_chip_accesses = 0xFFFFFFFF;
printf("number of total write accesses:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
l = totalbankwrites[i][j];
@@ -483,7 +462,7 @@ void memlatstat_print( )
/*AVERAGE MF LATENCY PER BANK*/
printf("average mf latency per bank:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
k = totalbankwrites[i][j] + totalbankreads[i][j];
@@ -497,7 +476,7 @@ void memlatstat_print( )
/*MAXIMUM MF LATENCY PER BANK*/
printf("maximum mf latency per bank:\n");
- for (i=0;i<gpu_n_mem ;i++ ) {
+ for (i=0;i<n_mem ;i++ ) {
printf("dram[%d]: ", i);
for (j=0;j<4 ;j++ ) {
printf("%10d", mf_max_lat_table[i][j]);
@@ -506,11 +485,11 @@ void memlatstat_print( )
}
}
- if (gpgpu_memlatency_stat & GPU_MEMLATSTAT_MC) {
+ if (m_memory_config->gpgpu_memlatency_stat & GPU_MEMLATSTAT_MC) {
printf("\nNumber of Memory Banks Accessed per Memory Operation per Warp (from 0):\n");
unsigned long long accum_MCBs_accessed = 0;
unsigned long long tot_mem_ops_per_warp = 0;
- for (i=0;i<= gpu_n_mem*gpu_mem_n_bk ; i++ ) {
+ for (i=0;i<= n_mem*gpu_mem_n_bk ; i++ ) {
accum_MCBs_accessed += i*num_MCBs_accessed[i];
tot_mem_ops_per_warp += num_MCBs_accessed[i];
printf("%d\t", num_MCBs_accessed[i]);
@@ -523,10 +502,10 @@ void memlatstat_print( )
printf("\nposition of mrq chosen\n");
- if (!gpgpu_dram_sched_queue_size)
+ if (!m_memory_config->gpgpu_dram_sched_queue_size)
j = 1024;
else
- j = gpgpu_dram_sched_queue_size;
+ j = m_memory_config->gpgpu_dram_sched_queue_size;
k=0;l=0;
for (i=0;i< j; i++ ) {
printf("%d\t", position_of_mrq_chosen[i]);
diff --git a/src/gpgpu-sim/mem_latency_stat.h b/src/gpgpu-sim/mem_latency_stat.h
index fd057c4..c228c6e 100644
--- a/src/gpgpu-sim/mem_latency_stat.h
+++ b/src/gpgpu-sim/mem_latency_stat.h
@@ -68,49 +68,79 @@
#ifndef MEM_LATENCY_STAT_H
#define MEM_LATENCY_STAT_H
-extern bool gpgpu_memlatency_stat;
+#include <stdio.h>
-extern unsigned max_mrq_latency;
-extern unsigned max_dq_latency;
-extern unsigned max_mf_latency;
-extern unsigned max_icnt2mem_latency;
-extern unsigned max_icnt2sh_latency;
-extern unsigned mrq_lat_table[32];
-extern unsigned dq_lat_table[32];
-extern unsigned mf_lat_table[32];
-extern unsigned icnt2mem_lat_table[24];
-extern unsigned icnt2sh_lat_table[24];
-extern unsigned mf_lat_pw_table[32]; //table storing values of mf latency Per Window
-extern unsigned mf_num_lat_pw;
-extern unsigned mf_tot_lat_pw; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window
-extern unsigned long long int mf_total_lat;
-extern unsigned long long int ** mf_total_lat_table; //mf latency sums[dram chip id][bank id]
-extern unsigned ** mf_max_lat_table; //mf latency sums[dram chip id][bank id]
-extern unsigned num_mfs;
-extern unsigned int ***bankwrites; //bankwrites[shader id][dram chip id][bank id]
-extern unsigned int ***bankreads; //bankreads[shader id][dram chip id][bank id]
-extern unsigned int **totalbankwrites; //bankwrites[dram chip id][bank id]
-extern unsigned int **totalbankreads; //bankreads[dram chip id][bank id]
-extern unsigned int **totalbankaccesses; //bankaccesses[dram chip id][bank id]
-extern unsigned int *requests_by_warp;
-extern unsigned int *num_MCBs_accessed; //tracks how many memory controllers are accessed whenever any thread in a warp misses in cache
-extern unsigned int *position_of_mrq_chosen; //position of mrq in m_queue chosen
-extern unsigned *mf_num_lat_pw_perwarp;
-extern unsigned *mf_tot_lat_pw_perwarp; //total latency summed up per window per warp. divide by mf_num_lat_pw_perwarp to obtain average latency Per Window
-extern unsigned long long int *mf_total_lat_perwarp;
-extern unsigned *num_mfs_perwarp;
-extern unsigned *acc_mrq_length;
+class memory_stats_t {
+public:
+ memory_stats_t( unsigned n_mem,
+ unsigned n_shader,
+ struct shader_core_config *shader_config,
+ struct memory_config *mem_config );
-extern unsigned ***mem_access_type_stats; // dram access type classification
+ void memlatstat_start( class mem_fetch *mf);
+ unsigned memlatstat_done( class mem_fetch *mf, unsigned n_warp_per_shader );
+ void memlatstat_icnt2sh_push( class mem_fetch *mf);
+ void memlatstat_read_done( class mem_fetch *mf, unsigned n_warp_per_shader);
+ void memlatstat_dram_access( class mem_fetch *mf );
+ void memlatstat_icnt2mem_pop( class mem_fetch *mf);
+ void memlatstat_lat_pw( unsigned n_shader, unsigned n_thread_per_shader, unsigned warp_size );
+ void memlatstat_print(unsigned n_mem, unsigned gpu_mem_n_bk);
-void memlatstat_init();
-void memlatstat_start(struct mem_fetch *mf);
-unsigned memlatstat_done(struct mem_fetch *mf);
-void memlatstat_icnt2sh_push(struct mem_fetch *mf);
-void memlatstat_read_done(struct mem_fetch *mf);
-void memlatstat_dram_access(struct mem_fetch *mf, unsigned dram_id, unsigned bank);
-void memlatstat_icnt2mem_pop(struct mem_fetch *mf);
-void memlatstat_lat_pw();
-void memlatstat_print();
+ void L2c_print_stat(unsigned n_mem);
+
+ void print( FILE *fp );
+
+ unsigned m_n_mem;
+ unsigned m_n_shader;
+
+ const struct shader_core_config *m_shader_config;
+ const struct memory_config *m_memory_config;
+
+ unsigned max_mrq_latency;
+ unsigned max_dq_latency;
+ unsigned max_mf_latency;
+ unsigned max_icnt2mem_latency;
+ unsigned max_icnt2sh_latency;
+ unsigned mrq_lat_table[32];
+ unsigned dq_lat_table[32];
+ unsigned mf_lat_table[32];
+ unsigned icnt2mem_lat_table[24];
+ unsigned icnt2sh_lat_table[24];
+ unsigned mf_lat_pw_table[32]; //table storing values of mf latency Per Window
+ unsigned mf_num_lat_pw;
+ unsigned max_warps;
+ unsigned mf_tot_lat_pw; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window
+ unsigned long long int mf_total_lat;
+ unsigned long long int ** mf_total_lat_table; //mf latency sums[dram chip id][bank id]
+ unsigned ** mf_max_lat_table; //mf latency sums[dram chip id][bank id]
+ unsigned num_mfs;
+ unsigned int ***bankwrites; //bankwrites[shader id][dram chip id][bank id]
+ unsigned int ***bankreads; //bankreads[shader id][dram chip id][bank id]
+ unsigned int **totalbankwrites; //bankwrites[dram chip id][bank id]
+ unsigned int **totalbankreads; //bankreads[dram chip id][bank id]
+ unsigned int **totalbankaccesses; //bankaccesses[dram chip id][bank id]
+ unsigned int *num_MCBs_accessed; //tracks how many memory controllers are accessed whenever any thread in a warp misses in cache
+ unsigned int *position_of_mrq_chosen; //position of mrq in m_queue chosen
+ unsigned *mf_num_lat_pw_perwarp;
+ unsigned *mf_tot_lat_pw_perwarp; //total latency summed up per window per warp. divide by mf_num_lat_pw_perwarp to obtain average latency Per Window
+ unsigned long long int *mf_total_lat_perwarp;
+ unsigned *num_mfs_perwarp;
+ unsigned *acc_mrq_length;
+
+ unsigned ***mem_access_type_stats; // dram access type classification
+
+
+ // stats
+ unsigned L2_write_miss;
+ unsigned L2_write_hit;
+ unsigned L2_read_hit;
+ unsigned L2_read_miss;
+ unsigned int *L2_cbtoL2length;
+ unsigned int *L2_cbtoL2writelength;
+ unsigned int *L2_L2tocblength;
+ unsigned int *L2_dramtoL2length;
+ unsigned int *L2_dramtoL2writelength;
+ unsigned int *L2_L2todramlength;
+};
#endif /*MEM_LATENCY_STAT_H*/
diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc
index 278ada4..711a6ab 100644
--- a/src/gpgpu-sim/scoreboard.cc
+++ b/src/gpgpu-sim/scoreboard.cc
@@ -11,16 +11,17 @@
//Constructor
-Scoreboard::Scoreboard( int sid, int n_warps )
+Scoreboard::Scoreboard( unsigned sid, unsigned n_warps )
{
- this->sid = sid;
+ m_sid = sid;
//Initialize size of table
reg_table.resize(n_warps);
}
// Print scoreboard contents
-void Scoreboard::printContents() {
- printf("scoreboard contents (sid=%d): \n", sid);
+void Scoreboard::printContents()
+{
+ printf("scoreboard contents (sid=%d): \n", m_sid);
for(unsigned i=0; i<reg_table.size(); i++) {
if(reg_table[i].size() == 0 ) continue;
printf(" wid = %d: ", i);
@@ -33,9 +34,10 @@ void Scoreboard::printContents() {
// Mark register as write-pending
-void Scoreboard::reserveRegister(int wid, int regnum) {
+void Scoreboard::reserveRegister(unsigned wid, unsigned regnum)
+{
if( !(reg_table[wid].find(regnum) == reg_table[wid].end()) ){
- printf("Error: trying to reserve an already reserved register (sid=%d, wid=%d, regnum=%d).", sid, wid, regnum);
+ printf("Error: trying to reserve an already reserved register (sid=%d, wid=%d, regnum=%d).", m_sid, wid, regnum);
assert(reg_table[wid].find(regnum) == reg_table[wid].end());
}
@@ -44,20 +46,19 @@ void Scoreboard::reserveRegister(int wid, int regnum) {
// Unmark register as write-pending
-void Scoreboard::releaseRegister(int wid, int regnum) {
+void Scoreboard::releaseRegister(unsigned wid, unsigned regnum)
+{
if( !(reg_table[wid].find(regnum) != reg_table[wid].end()) ) {
- printf("Error: trying to release an unreserved register (sid=%d, wid=%d, regnum=%d).", sid, wid, regnum);
+ printf("Error: trying to release an unreserved register (sid=%d, wid=%d, regnum=%d).", m_sid, wid, regnum);
assert(reg_table[wid].find(regnum) != reg_table[wid].end());
}
-
reg_table[wid].erase(regnum);
}
// Reserve registers for an instruction
-void Scoreboard::reserveRegisters(int wid, void* inst_void) {
- inst_t *inst = (inst_t *) inst_void;
-
+void Scoreboard::reserveRegisters(unsigned wid, const class inst_t* inst)
+{
// Reserve registers
if(inst->out[0] > 0) reserveRegister(wid, inst->out[0]);
if(inst->out[1] > 0) reserveRegister(wid, inst->out[1]);
@@ -66,19 +67,22 @@ void Scoreboard::reserveRegisters(int wid, void* inst_void) {
}
// Release registers for an instruction
-void Scoreboard::releaseRegisters(int wid, void *inst_void) {
- inst_t *inst = (inst_t *) inst_void;
-
+void Scoreboard::releaseRegisters(unsigned wid, const class inst_t *inst)
+{
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]);
if(inst->out[3] > 0) releaseRegister(wid, inst->out[3]);
}
-// Checks to see if registers used by an instruction are reserved in the scoreboard
-bool Scoreboard::checkCollision(int wid, void *inst_void) {
- inst_t *inst = (inst_t *) inst_void;
-
+/**
+ * Checks to see if registers used by an instruction are reserved in the scoreboard
+ *
+ * @return
+ * true if WAW or RAW hazard (no WAR since in-order issue)
+ **/
+bool Scoreboard::checkCollision( unsigned wid, const class inst_t *inst )
+{
// Get list of all input and output registers
std::set<int> inst_regs;
@@ -94,32 +98,16 @@ bool Scoreboard::checkCollision(int wid, void *inst_void) {
if(inst->ar1 > 0) inst_regs.insert(inst->ar1);
if(inst->ar2 > 0) inst_regs.insert(inst->ar2);
- /*
- printf("Inst registers: ");
- std::set<int>::iterator it;
- for ( it=inst_regs.begin() ; it != inst_regs.end(); it++ )
- printf("%d ", *it);
- printf("\n");
- */
-
// Check for collision, get the intersection of reserved registers and instruction registers
- //std::set<int> reg_intr;
std::set<int>::iterator it2;
for ( it2=inst_regs.begin() ; it2 != inst_regs.end(); it2++ )
if(reg_table[wid].find(*it2) != reg_table[wid].end()) {
- //reg_intr.insert(*it2);
return true;
}
-
return false;
+}
- /*
- printf("Intersection registers: ");
- std::set<int>::iterator it3;
- for ( it3=reg_intr.begin() ; it3 != reg_intr.end(); it3++ )
- printf("%d ", *it3);
- printf("\n");
- */
-
-
+bool Scoreboard::pendingWrites(unsigned wid) const
+{
+ return !reg_table[wid].empty();
}
diff --git a/src/gpgpu-sim/scoreboard.h b/src/gpgpu-sim/scoreboard.h
index 4139948..6cec22c 100644
--- a/src/gpgpu-sim/scoreboard.h
+++ b/src/gpgpu-sim/scoreboard.h
@@ -14,29 +14,28 @@
#ifndef SCOREBOARD_H_
#define SCOREBOARD_H_
-typedef unsigned op_type;
+#include "../abstract_hardware_model.h"
-class Scoreboard
-{
- private:
- int sid; // Shader id
- // Table to keep track of write-pending registers
- // Indexed by warp id (wid)
- std::vector< std::set<int> > reg_table;
+class Scoreboard {
+public:
+ Scoreboard( unsigned sid, unsigned n_warps );
- void reserveRegister(int wid, int regnum);
- void releaseRegister(int wid, int regnum);
+ void printContents();
- public:
- Scoreboard( int sid, int n_warps );
+ void reserveRegisters(unsigned wid, const inst_t *inst);
+ void releaseRegisters(unsigned wid, const inst_t *inst);
- void printContents();
+ bool checkCollision(unsigned wid, const inst_t *inst);
+ bool pendingWrites(unsigned wid) const;
+private:
+ void reserveRegister(unsigned wid, unsigned regnum);
+ void releaseRegister(unsigned wid, unsigned regnum);
- void reserveRegisters(int wid, void *inst_void);
- void releaseRegisters(int wid, void *inst_void);
-
- bool checkCollision(int wid, void *inst_void);
+ unsigned m_sid;
+ // keeps track of pending writes to registers
+ // indexed by warp id
+ std::vector< std::set<int> > reg_table;
};
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 5f465ed..1f2be5a 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -87,62 +87,8 @@
#define PRIORITIZE_MSHR_OVER_WB 1
#define MAX(a,b) (((a)>(b))?(a):(b))
-extern bool gpgpu_stall_on_use;
-enum mem_stage_access_type {
- C_MEM,
- T_MEM,
- S_MEM,
- G_MEM_LD,
- L_MEM_LD,
- G_MEM_ST,
- L_MEM_ST,
- N_MEM_STAGE_ACCESS_TYPE
-};
-
-enum mem_stage_stall_type {
- NO_RC_FAIL = 0,
- BK_CONF,
- MSHR_RC_FAIL,
- ICNT_RC_FAIL,
- COAL_STALL,
- WB_ICNT_RC_FAIL,
- WB_CACHE_RSRV_FAIL,
- N_MEM_STAGE_STALL_TYPE
-};
-unsigned int gpu_stall_shd_mem_breakdown[N_MEM_STAGE_ACCESS_TYPE][N_MEM_STAGE_STALL_TYPE] = { {0} };
-unsigned warp_size = 4;
-int pipe_simd_width;
-unsigned int *shader_cycle_distro;
-unsigned int g_waiting_at_barrier = 0;
-unsigned int gpgpu_shmem_size;
-unsigned int gpgpu_shader_registers;
-unsigned int gpgpu_shader_cta;
-unsigned int gpgpu_n_load_insn = 0;
-unsigned int gpgpu_n_store_insn = 0;
-unsigned int gpgpu_n_shmem_insn = 0;
-unsigned int gpgpu_n_tex_insn = 0;
-unsigned int gpgpu_n_const_insn = 0;
-unsigned int gpgpu_n_param_insn = 0;
-unsigned int gpgpu_multi_unq_fetches = 0;
-bool gpgpu_shmem_bkconflict;
-unsigned int gpgpu_n_shmem_bkconflict = 0;
-int gpgpu_n_shmem_bank = 16;
-bool gpgpu_cache_bkconflict;
-unsigned int gpgpu_n_cache_bkconflict = 0;
-unsigned int gpgpu_n_cmem_portconflict = 0;
-int gpgpu_n_cache_bank;
-int gpgpu_warpdistro_shader;
-int gpgpu_interwarp_mshr_merge;
-int gpgpu_n_intrawarp_mshr_merge = 0;
-int gpgpu_n_partial_writes = 0;
-int gpgpu_shmem_port_per_bank;
-int gpgpu_cache_port_per_bank;
-int gpgpu_const_port_per_bank;
-int gpgpu_shmem_pipe_speedup;
-unsigned int gpu_max_cta_per_shader = 8;
-unsigned int gpu_padded_cta_size = 32;
-int gpgpu_local_mem_map;
+unsigned mem_access_t::next_access_uid = 0;
/////////////////////////////////////////////////////////////////////////////
/*-------------------------------------------------------------------------*/
@@ -150,312 +96,276 @@ int gpgpu_local_mem_map;
static const char* MSHR_Status_str[] = {
"INITIALIZED",
+ "INVALID",
"IN_ICNT2MEM",
- "IN_ICNTOL2QUEUE",
+ "IN_CBTOL2QUEUE",
"IN_L2TODRAMQUEUE",
"IN_DRAM_REQ_QUEUE",
+ "IN_DRAMRETURN_Q",
"IN_DRAMTOL2QUEUE",
- "IN_L2TOICNTQUEUE_HIT",
- "IN_L2TOICNTQUEUE_MISS",
+ "IN_L2TOCBQUEUE_HIT",
+ "IN_L2TOCBQUEUE_MISS",
"IN_ICNT2SHADER",
"FETCHED",
};
-// a helper function that deduce if a mshr contains an atomic operation
-bool isatomic(mshr_entry_t *mshr)
+void mshr_lookup::insert(mshr_entry* mshr)
{
- return (mshr->insts[0].callback.function != NULL);
+ using namespace std;
+ new_addr_type tag_addr = mshr->get_addr();
+ m_lut.insert(make_pair(tag_addr, mshr));
}
-#include <map>
-#include <utility>
-#include <algorithm>
-// a class that speeds up mshr lookup with a C++ multimap
-class mshr_lookup {
-private:
- typedef std::multimap<unsigned long long int, mshr_entry*> mshr_lut_t;
- mshr_lut_t m_lut; // multiple mshr entries can have the same tag
-private:
- void insert(mshr_entry* mshr)
- {
- using namespace std;
- unsigned long long int tag_addr = mshr->addr;
- m_lut.insert(make_pair(tag_addr, mshr));
+mshr_entry* mshr_lookup::lookup( new_addr_type addr ) const
+{
+ std::pair<mshr_lut_t::const_iterator, mshr_lut_t::const_iterator> i_range = m_lut.equal_range(addr);
+ if (i_range.first == i_range.second) {
+ return NULL;
+ } else {
+ mshr_lut_t::const_iterator i_lut = i_range.first;
+ return i_lut->second->get_last_merged();
}
+}
- mshr_entry* lookup(unsigned long long int addr) const
- {
- using namespace std;
- // mshr_lut_t::const_iterator i_lut = m_lut.find(tag_addr);
- pair<mshr_lut_t::const_iterator, mshr_lut_t::const_iterator> i_range = m_lut.equal_range(addr);
- if (i_range.first == i_range.second) {
- return NULL;
- } else {
- mshr_lut_t::const_iterator i_lut = i_range.first;
- mshr_entry* mshr_hit = i_lut->second;
- //follow match to end of merge chain:
- //this won't really work for different sized requests, ie can't merge a 64b request to a 32b
- while (mshr_hit->merged_requests) {
- mshr_hit = mshr_hit->merged_requests;
- }
- return mshr_hit;
- }
- }
-
- void remove(mshr_entry* mshr)
- {
- using namespace std;
- std::pair<mshr_lut_t::iterator, mshr_lut_t::iterator> i_range = m_lut.equal_range(mshr->addr);
+void mshr_lookup::remove(mshr_entry* mshr)
+{
+ using namespace std;
+ std::pair<mshr_lut_t::iterator, mshr_lut_t::iterator> i_range = m_lut.equal_range(mshr->get_addr());
- assert(i_range.first != i_range.second);
+ assert(i_range.first != i_range.second);
- for (mshr_lut_t::iterator i_lut = i_range.first; i_lut != i_range.second; ++i_lut) {
- if (i_lut->second == mshr) {
- m_lut.erase(i_lut);
- break;
- }
- }
- }
-public:
- //checks if we should do mshr merging for this mshr
- bool can_merge(mshr_entry_t * mshr)
- {
- if (mshr->iswrite) return false; // can't merge a write
- if (isatomic(mshr)) return false; // can't merge a atomic operation
- bool interwarp_mshr_merge = gpgpu_interwarp_mshr_merge & GLOBAL_MSHR_MERGE;
- if (mshr->istexture) {
- interwarp_mshr_merge = gpgpu_interwarp_mshr_merge & TEX_MSHR_MERGE;
- } else if (mshr->isconst) {
- interwarp_mshr_merge = gpgpu_interwarp_mshr_merge & CONST_MSHR_MERGE;
+ for (mshr_lut_t::iterator i_lut = i_range.first; i_lut != i_range.second; ++i_lut) {
+ if (i_lut->second == mshr) {
+ m_lut.erase(i_lut);
+ break;
}
- return interwarp_mshr_merge;
}
+}
- void mshr_fast_lookup_insert(mshr_entry* mshr)
- {
- if (!can_merge(mshr)) return;
- insert(mshr);
- }
+//checks if we should do mshr merging for this mshr
+bool mshr_lookup::can_merge(mshr_entry * mshr)
+{
+ if (mshr->iswrite())
+ return false; // can't merge a write
+ if (mshr->isatomic())
+ return false; // can't merge a atomic operation
+ bool interwarp_mshr_merge = m_shader_config->gpgpu_interwarp_mshr_merge & GLOBAL_MSHR_MERGE;
+ if (mshr->isinst())
+ interwarp_mshr_merge=true;
+ else if (mshr->istexture())
+ interwarp_mshr_merge = m_shader_config->gpgpu_interwarp_mshr_merge & TEX_MSHR_MERGE;
+ else if (mshr->isconst())
+ interwarp_mshr_merge = m_shader_config->gpgpu_interwarp_mshr_merge & CONST_MSHR_MERGE;
+ return interwarp_mshr_merge;
+}
+
+void mshr_lookup::mshr_fast_lookup_insert(mshr_entry* mshr)
+{
+ if (!can_merge(mshr))
+ return;
+ insert(mshr);
+}
- void mshr_fast_lookup_remove(mshr_entry* mshr)
- {
- if (!can_merge(mshr)) return;
- remove(mshr);
- }
+void mshr_lookup::mshr_fast_lookup_remove(mshr_entry* mshr)
+{
+ if (!can_merge(mshr))
+ return;
+ remove(mshr);
+}
- mshr_entry* shader_get_mergeable_mshr(mshr_entry_t* mshr)
- {
- if (!can_merge(mshr)) return NULL;
- return lookup(mshr->addr);
- }
-};
+mshr_entry* mshr_lookup::shader_get_mergeable_mshr(mshr_entry* mshr)
+{
+ if (!can_merge(mshr)) return NULL;
+ return lookup(mshr->get_addr());
+}
-class mem_access_t;
-int is_tex ( int space );
-int is_const ( int space );
-int is_local ( int space );
-#include <iostream>
-class mshr_shader_unit{
-public:
- mshr_shader_unit(unsigned max_mshr): m_max_mshr(max_mshr), m_max_mshr_used(0){
- m_mshrs.resize(max_mshr);
- for (std::vector<mshr_entry_t>::iterator i = m_mshrs.begin(); i != m_mshrs.end(); i++) m_free_list.push_back(i);
- }
- bool has_mshr(unsigned num){return (num <= m_free_list.size());}
- unsigned mshr_used(){ return m_max_mshr - m_free_list.size();}
- mshr_entry_t* add_mshr(mem_access_t &access, inst_t* warp);
+mshr_shader_unit::mshr_shader_unit( const shader_core_config *config ): m_max_mshr_used(0), m_mshr_lookup(config)
+{
+ m_shader_config=config;
+ m_mshrs.resize(config->n_mshr_per_shader);
+ unsigned n=0;
+ for (std::vector<mshr_entry>::iterator i = m_mshrs.begin(); i != m_mshrs.end(); i++) {
+ mshr_entry &mshr = *i;
+ mshr.set_id(n++);
+ m_free_list.push_back(&mshr);
+ }
+}
- //return queue access; (includes texture pipeline return)
- mshr_entry_t* return_head(){
- if (has_return())
- return &(*(choose_return_queue().front()));
- else
- return NULL;
- }
- //return queue pop; (includes texture pipeline return)
- void pop_return_head() {
- free_mshr(return_head()->this_mshr);
- choose_return_queue().pop_front();
- }
+mshr_entry* mshr_shader_unit::return_head()
+{
+ if (has_return())
+ return &(*choose_return_queue().front());
+ else
+ return NULL;
+}
- static void mshr_update_status(mshr_entry *mshr, enum mshr_status new_status );
- void mshr_return_from_mem(mshr_entry *mshr);
- void check_mshr(mshr_entry *mshr){
- assert(find(m_free_list.begin(),m_free_list.end(),mshr->this_mshr)==m_free_list.end());
- assert(mshr->insts.size());
- }
- unsigned get_max_mshr_used(){return m_max_mshr_used;}
- void print(FILE* fp, shader_core_ctx_t* shader);
-private:
- typedef std::vector<mshr_entry_t> mshr_storage_type;//list might be less complicated, but slower?
- mshr_storage_type m_mshrs;
- std::deque< mshr_storage_type::iterator > m_free_list;
- std::deque< mshr_storage_type::iterator > m_mshr_return_queue;
- std::deque< mshr_storage_type::iterator > m_texture_mshr_pipeline;
- unsigned m_max_mshr;
- unsigned m_max_mshr_used;
- mshr_lookup m_mshr_lookup;
+void mshr_shader_unit::pop_return_head()
+{
+ free_mshr(return_head());
+ choose_return_queue().pop_front();
+}
- mshr_entry_t *alloc_free_mshr(bool istexture){
- assert(!m_free_list.empty());
- std::vector<mshr_entry_t>::iterator i = m_free_list.back();
- m_free_list.pop_back();
- i->this_mshr = i;
- if (istexture) {
- //put in texture pipeline
- m_texture_mshr_pipeline.push_back(i);
- }
- if (mshr_used() > m_max_mshr_used) m_max_mshr_used = mshr_used();
- return &(*i);
- }
- void free_mshr(std::vector<mshr_entry_t>::iterator &i){
- //clean up up for next time, since not reallocating memory.
- m_mshr_lookup.mshr_fast_lookup_remove(&(*i)); //need to remove before clearing insts, as they are accessed
- i->insts.clear(); //add expects this to be clear
- m_free_list.push_back(i);
- }
- bool has_return() { return (not m_mshr_return_queue.empty()) or ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched());}
- std::deque< std::vector<mshr_entry_t>::iterator > & choose_return_queue() {
- //prioritize a ready texture over a global/const...
- if ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched()) return m_texture_mshr_pipeline;
- assert(!m_mshr_return_queue.empty());
- return m_mshr_return_queue;
- }
-};
+mshr_entry *mshr_shader_unit::alloc_free_mshr(bool istexture)
+{
+ assert(!m_free_list.empty());
+ mshr_entry *mshr = m_free_list.back();
+ m_free_list.pop_back();
+ if (istexture)
+ m_texture_mshr_pipeline.push_back(mshr);
+ if (mshr_used() > m_max_mshr_used)
+ m_max_mshr_used = mshr_used();
+ return mshr;
+}
+void mshr_shader_unit::free_mshr( mshr_entry *mshr )
+{
+ //clean up up for next time, since not reallocating memory.
+ m_mshr_lookup.mshr_fast_lookup_remove(mshr);
+ mshr->clear();
+ m_free_list.push_back(mshr);
+}
+unsigned mshr_shader_unit::mshr_used() const
+{
+ return m_shader_config->n_mshr_per_shader - m_free_list.size();
+}
-void mshr_shader_unit::mshr_update_status(mshr_entry *mshr, enum mshr_status new_status ) {
- mshr->status = new_status;
-#if DEBUGL1MISS
- printf("cycle %d Addr %x %d \n",gpu_sim_cycle,CACHE_TAG_OF_64(mshr->addr),new_status);
-#endif
- mshr_entry * merged_req = mshr->merged_requests;
- while (merged_req) {
- merged_req->status = new_status;
- merged_req = merged_req->merged_requests;
- }
+std::deque<mshr_entry*> &mshr_shader_unit::choose_return_queue()
+{
+ // prioritize a ready texture over a global/const...
+ if ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched())
+ return m_texture_mshr_pipeline;
+ assert(!m_mshr_return_queue.empty());
+ return m_mshr_return_queue;
}
-inline void mshr_shader_unit::mshr_return_from_mem(mshr_entry *mshr){
- mshr_update_status(mshr, FETCHED);
- if (not mshr->istexture) {
+void mshr_shader_unit::mshr_return_from_mem(mshr_entry *mshr)
+{
+ mshr->set_status( FETCHED );
+ if ( not mshr->istexture() ) {
//place in return queue
- m_mshr_return_queue.push_back(mshr->this_mshr);
- //place all merged requests in return queue
- mshr_entry * merged_req = mshr->merged_requests;
- while (merged_req) {
- m_mshr_return_queue.push_back(merged_req->this_mshr);
- merged_req = merged_req->merged_requests;
- }
+ mshr->add_to_queue( m_mshr_return_queue );
}
}
-void mshr_return_from_mem(shader_core_ctx_t * shader, mshr_entry_t* mshr){
- shader->mshr_unit->mshr_return_from_mem(mshr);
+void shader_core_ctx::mshr_print(FILE* fp, unsigned mask)
+{
+ m_mshr_unit->print(fp, this, mask);
}
-unsigned get_max_mshr_used(shader_core_ctx_t * shader){
- return shader->mshr_unit->get_max_mshr_used();
+void mshr_shader_unit::print(FILE* fp, shader_core_ctx* shader, unsigned mask)
+{
+ unsigned n=0;
+ unsigned num_outstanding = 0;
+ for (mshr_storage_type::iterator it = m_mshrs.begin(); it != m_mshrs.end(); it++,n++) {
+ mshr_entry *mshr = &(*it);
+ if (find(m_free_list.begin(),m_free_list.end(), mshr) == m_free_list.end()) {
+ num_outstanding++;
+ mshr->print(fp,mask);
+ }
+ }
+ fprintf(fp,"\nTotal outstanding memory requests = %u\n", num_outstanding );
}
+unsigned char shader_core_ctx::fq_push(unsigned long long int addr,
+ int bsize,
+ unsigned char write,
+ partial_write_mask_t partial_write_mask,
+ int wid,
+ mshr_entry* mshr,
+ int cache_hits_waiting,
+ enum mem_access_type mem_acc,
+ address_type pc)
+{
+ assert(write || (partial_write_mask == NO_PARTIAL_WRITE));
+ int nbytes_L2 = m_gpu->get_L2_linesize();
+ mem_fetch *mf = new mem_fetch(addr,
+ bsize,
+ nbytes_L2,
+ m_sid,
+ m_tpc,
+ wid,
+ cache_hits_waiting,
+ mshr,
+ write,
+ partial_write_mask,
+ mem_acc,
+ write?WT_REQ:RD_REQ,
+ pc);
+ if (mshr) mshr->set_mf(mf);
+
+ // stats
+ if (write) made_write_mfs++;
+ else made_read_mfs++;
+ switch (mem_acc) {
+ case CONST_ACC_R: m_stats->gpgpu_n_mem_const++; break;
+ case TEXTURE_ACC_R: m_stats->gpgpu_n_mem_texture++; break;
+ case GLOBAL_ACC_R: m_stats->gpgpu_n_mem_read_global++; break;
+ case GLOBAL_ACC_W: m_stats->gpgpu_n_mem_write_global++; break;
+ case LOCAL_ACC_R: m_stats->gpgpu_n_mem_read_local++; break;
+ case LOCAL_ACC_W: m_stats->gpgpu_n_mem_write_local++; break;
+ case INST_ACC_R: m_stats->gpgpu_n_mem_read_inst++; break;
+ default: assert(0);
+ }
-void mshr_print(FILE* fp, shader_core_ctx_t *shader) {
- shader->mshr_unit->print(fp, shader);
+ return(m_gpu->issue_mf_from_fq(mf));
}
-void mshr_shader_unit::print(FILE* fp, shader_core_ctx_t* shader){
- for (mshr_storage_type::iterator it = m_mshrs.begin(); it != m_mshrs.end(); it++) {
- //valid if not in free list;
- if (find(m_free_list.begin(),m_free_list.end(), it) == m_free_list.end()) {
- mshr_entry *mshr = &(*it);
- fprintf(fp, "MSHR(%d): %s Addr:0x%llx Fetched:%d Merged:%d Status:%s\n",
- shader->sid,
- (mshr->iswrite)? "=>" : "<=",
- mshr->addr, mshr->fetched(),
- (mshr->merged_requests != NULL or mshr->merged_on_other_reqest), MSHR_Status_str[mshr->status]);
- for (unsigned i = 0; i < mshr->insts.size(); i++) {
- fprintf(fp,"\tthread: UID:%d HW:%d ReqAddr:0x%llx\n", mshr->insts[i].uid, mshr->insts[i].hw_thread_id, mshr->insts[i].memreqaddr);
- }
- }
- }
+inst_t *shader_core_ctx::first_valid_thread( inst_t *warp )
+{
+ for(unsigned t=0; t < m_config->warp_size; t++ )
+ if( warp[t].hw_thread_id != -1 )
+ return warp+t;
+ return NULL;
}
-void mshr_update_status(mshr_entry* mshr, enum mshr_status new_status) {
- mshr_entry *merged_req;
- mshr->status = new_status;
-#if DEBUGL1MISS
- printf("cycle %d Addr %x %d \n",gpu_sim_cycle,CACHE_TAG_OF_64(mshr->addr),new_status);
-#endif
- merged_req = mshr->merged_requests;
- while (merged_req) {
- merged_req->status = new_status;
- merged_req = merged_req->merged_requests;
- }
+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 )
+{
-inst_t create_nop_inst() // just because C++ does not have designated initializer list....
+ 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 )
{
- inst_t nop_inst;
- nop_inst.pc = 0;
- nop_inst.op=NO_OP;
- memset(nop_inst.out, 0, sizeof(nop_inst.out));
- memset(nop_inst.in, 0, sizeof(nop_inst.in));
- nop_inst.is_vectorin=0;
- nop_inst.is_vectorout=0;
- nop_inst.memreqaddr=0;
- nop_inst.reg_bank_access_pending=0;
- nop_inst.reg_bank_conflict_stall_checked=0,
- nop_inst.hw_thread_id=-1;
- nop_inst.wlane=-1;
- nop_inst.uid = (unsigned)-1;
- nop_inst.priority = (unsigned)-1;
- nop_inst.ptx_thd_info = NULL;
- nop_inst.warp_active_mask = 0;
- nop_inst.ts_cycle = 0;
- nop_inst.id_cycle = 0;
- nop_inst.ex_cycle = 0;
- nop_inst.mm_cycle = 0;
- nop_inst.cache_miss = false;
- nop_inst.space = memory_space_t();
- nop_inst.cycles = 0;
- return nop_inst;
+ for( unsigned t=0; t < m_config->warp_size; t++)
+ warp[t] = inst_t();
}
-static inst_t nop_inst = create_nop_inst();
+bool shader_core_ctx::pipeline_regster_empty( inst_t *reg )
+{
+ return first_valid_thread(reg) == NULL;
+}
-inst_t *first_valid_thread( inst_t *warp )
+void shader_core_ctx::L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const
{
- for(unsigned t=0; t < ::warp_size; t++ )
- if( warp[t].hw_thread_id != -1 )
- return warp+t;
- return NULL;
+ shd_cache_print(m_L1D,fp,total_accesses,total_misses);
}
-void move_warp( inst_t *dst, inst_t *src )
+void shader_core_ctx::L1texcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const
{
- memcpy(dst,src,::warp_size * sizeof(inst_t));
- for( unsigned t=0; t < ::warp_size; t++)
- src[t] = nop_inst;
+ shd_cache_print(m_L1T,fp,total_accesses,total_misses);
}
-bool pipeline_regster_empty( inst_t *reg )
+void shader_core_ctx::L1constcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const
{
- return first_valid_thread(reg) == NULL;
+ shd_cache_print(m_L1C,fp,total_accesses,total_misses);
}
-std::list<unsigned> get_regs_written( inst_t *warp )
+std::list<unsigned> shader_core_ctx::get_regs_written( const inst_t &fvt ) const
{
std::list<unsigned> result;
- inst_t *fvi = first_valid_thread(warp);
- if( fvi == NULL )
- return result;
for( unsigned op=0; op < 4; op++ ) {
- int reg_num = fvi->arch_reg[op]; // this math needs to match that used in function_info::ptx_decode_inst
+ int reg_num = fvt.arch_reg[op]; // this math needs to match that used in function_info::ptx_decode_inst
if( reg_num >= 0 ) // valid register
result.push_back(reg_num);
}
@@ -471,694 +381,396 @@ int log2i(int n) {
return lg;
}
-shader_core_ctx_t* shader_create( const char *name, int sid,
- unsigned int n_threads,
- unsigned int n_mshr,
- fq_push_t fq_push,
- fq_has_buffer_t fq_has_buffer,
- unsigned int model )
-{
- shader_core_ctx_t *sc;
- sc = (shader_core_ctx_t*)calloc(sizeof(shader_core_ctx_t),1);
- sc = new (sc) shader_core_ctx(name,sid,n_threads,n_mshr,fq_push,fq_has_buffer,model,
- gpu_n_warp_per_shader,gpgpu_shader_cta);
- return sc;
-}
-
-shader_core_ctx::shader_core_ctx( const char *name, int sid,
- unsigned int n_threads,
- unsigned int n_mshr,
- fq_push_t fq_push,
- fq_has_buffer_t fq_has_buffer,
- unsigned model,
- unsigned max_warps_per_cta, unsigned max_cta_per_core )
- : m_barriers( max_warps_per_cta, max_cta_per_core )
+shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
+ const char *name,
+ unsigned shader_id,
+ unsigned tpc_id,
+ const struct shader_core_config *config,
+ struct shader_core_stats *stats )
+ : m_barriers( config->max_warps_per_shader, config->max_cta_per_core )
{
- shader_core_ctx *sc = this;
- assert( !((model == DWF) && gpgpu_operand_collector) );
-
- int i;
- unsigned int shd_n_set;
- unsigned int shd_linesize;
- unsigned int shd_n_assoc;
- unsigned char shd_policy;
-
- unsigned int l1tex_cache_n_set; //L1 texture cache parameters
- unsigned int l1tex_cache_linesize;
- unsigned int l1tex_cache_n_assoc;
- unsigned char l1tex_cache_policy;
+ m_gpu = gpu;
+ m_config = config;
+ m_stats = stats;
+ unsigned warp_size=config->warp_size;
+ assert( !((config->model == DWF) && m_config->gpgpu_operand_collector) );
- unsigned int l1const_cache_n_set; //L1 constant cache parameters
- unsigned int l1const_cache_linesize;
- unsigned int l1const_cache_n_assoc;
- unsigned char l1const_cache_policy;
-
- if ( gpgpu_cuda_sim ) {
- unsigned cta_size = ptx_sim_cta_size();
- if ( cta_size > n_threads ) {
- printf("Execution error: Shader kernel CTA (block) size is too large for microarch config.\n");
- printf(" This can cause problems with applications that use __syncthreads.\n");
- printf(" CTA size (x*y*z) = %u, n_threads = %u\n", cta_size, n_threads );
- printf(" => either change -gpgpu_shader argument in gpgpusim.config file or\n");
- printf(" modify the CUDA source to decrease the kernel block size.\n");
- abort();
- }
- }
-
- sc->name = name;
- sc->sid = sid;
-
- sc->RR_k = 0;
-
- sc->model = model;
-
- sc->pipeline_reg = (inst_t**) calloc(N_PIPELINE_STAGES, sizeof(inst_t*));
+ 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++) {
- sc->pipeline_reg[j] = (inst_t*) calloc(warp_size, sizeof(inst_t));
- for (unsigned i=0; i<warp_size; i++) {
- sc->pipeline_reg[j][i] = nop_inst;
- }
+ 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();
}
- if (gpgpu_pre_mem_stages) {
- sc->pre_mem_pipeline = (inst_t**) calloc(gpgpu_pre_mem_stages+1, sizeof(inst_t*));
- for (unsigned j = 0; j<=gpgpu_pre_mem_stages; j++) {
- sc->pre_mem_pipeline[j] = (inst_t*) calloc(pipe_simd_width, sizeof(inst_t));
- for (int i=0; i<pipe_simd_width; i++) {
- sc->pre_mem_pipeline[j][i] = nop_inst;
+ 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();
}
}
}
- sc->n_threads = n_threads;
- sc->thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), n_threads);
- sc->not_completed = 0;
+ m_thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader);
+ m_not_completed = 0;
- unsigned n_warp = (n_threads/warp_size) + ((n_threads%warp_size)?1:0);
- sc->warp.resize(n_warp, shd_warp_t(warp_size));
- for (unsigned j = 0; j < n_warp; j++) {
- sc->warp[j].wid = j;
- }
+ m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size));
- sc->n_active_cta = 0;
- for (i = 0; i<MAX_CTA_PER_SHADER; i++ ) {
- sc->cta_status[i]=0;
+ 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;
}
- //Warp variable initializations
- sc->next_warp = 0;
- sc->branch_priority = 0;
- sc->max_branch_priority = (int*) malloc(sizeof(int)*n_threads);
+ #define STRSIZE 1024
+ char L1D_name[STRSIZE];
+ char L1T_name[STRSIZE];
+ char L1C_name[STRSIZE];
+ char L1I_name[STRSIZE];
- for (unsigned i = 0; i<n_threads; i++) {
- sc->max_branch_priority[i] = INT_MAX;
- sc->thread[i].id = i;
+ snprintf(L1D_name, STRSIZE, "L1D_%03d", m_sid);
+ m_L1D = shd_cache_create(L1D_name,m_config->gpgpu_cache_dl1_opt,1,0,m_config->gpgpu_cache_wt_through?write_through:write_back);
+ shd_cache_bind_logger(m_L1D, m_sid, get_shader_normal_cache_id());
- sc->thread[i].warp_priority = sc->max_branch_priority[i];
- sc->thread[i].avail4fetch = 0;
- sc->thread[i].m_waiting_at_barrier = 0;
+ snprintf(L1T_name, STRSIZE, "L1T_%03d", m_sid);
+ m_L1T = shd_cache_create(L1T_name,m_config->gpgpu_cache_texl1_opt,1,0, no_writes );
+ shd_cache_bind_logger(m_L1T, m_sid, get_shader_texture_cache_id());
+ ptx_set_tex_cache_linesize(m_L1T->line_sz);
- sc->thread[i].ptx_thd_info = NULL;
- sc->thread[i].cta_id = -1;
- }
-
- sscanf(gpgpu_cache_dl1_opt,"%d:%d:%d:%c",
- &shd_n_set, &shd_linesize, &shd_n_assoc, &shd_policy);
- sscanf(gpgpu_cache_texl1_opt,"%d:%d:%d:%c",
- &l1tex_cache_n_set, &l1tex_cache_linesize, &l1tex_cache_n_assoc, &l1tex_cache_policy);
- sscanf(gpgpu_cache_constl1_opt,"%d:%d:%d:%c",
- &l1const_cache_n_set, &l1const_cache_linesize, &l1const_cache_n_assoc, &l1const_cache_policy);
-#define STRSIZE 32
- char L1c_name[STRSIZE];
- char L1texc_name[STRSIZE];
- char L1constc_name[STRSIZE];
- snprintf(L1c_name, STRSIZE, "L1c_%03d", sc->sid);
- sc->L1cache = shd_cache_create(L1c_name,shd_n_set,shd_n_assoc,shd_linesize,shd_policy,1,0,
- gpgpu_cache_wt_through?write_through:write_back);
- shd_cache_bind_logger(sc->L1cache, sc->sid, get_shader_normal_cache_id());
- snprintf(L1texc_name, STRSIZE, "L1texc_%03d", sc->sid);
- sc->L1texcache = shd_cache_create(L1texc_name,l1tex_cache_n_set,l1tex_cache_n_assoc,l1tex_cache_linesize,l1tex_cache_policy,1,0, no_writes );
- shd_cache_bind_logger(sc->L1texcache, sc->sid, get_shader_texture_cache_id());
- snprintf(L1constc_name, STRSIZE, "L1constc_%03d", sc->sid);
- sc->L1constcache = shd_cache_create(L1constc_name,l1const_cache_n_set,l1const_cache_n_assoc,l1const_cache_linesize,l1const_cache_policy,1,0, no_writes );
- shd_cache_bind_logger(sc->L1constcache, sc->sid, get_shader_constant_cache_id());
- //at this point, should set the parameters used by addressing schemes of all textures
- ptx_set_tex_cache_linesize(l1tex_cache_linesize);
-
- sc->mshr_unit = new mshr_shader_unit(gpu_n_mshr_per_shader);
+ snprintf(L1C_name, STRSIZE, "L1C_%03d", m_sid);
+ m_L1C = shd_cache_create(L1C_name,m_config->gpgpu_cache_constl1_opt,1,0, no_writes );
+ shd_cache_bind_logger(m_L1C, m_sid, get_shader_constant_cache_id());
- sc->fq_push = fq_push;
- sc->fq_has_buffer = fq_has_buffer;
-
- sc->pdom_warp = (pdom_warp_ctx_t*)calloc(n_threads / warp_size, sizeof(pdom_warp_ctx_t));
- for (unsigned i = 0; i < n_threads / warp_size; ++i) {
- sc->pdom_warp[i].m_stack_top = 0;
- sc->pdom_warp[i].m_pc = (address_type*)calloc(warp_size * 2, sizeof(address_type));
- sc->pdom_warp[i].m_calldepth = (unsigned int*)calloc(warp_size * 2, sizeof(unsigned int));
- sc->pdom_warp[i].m_active_mask = (unsigned int*)calloc(warp_size * 2, sizeof(unsigned int));
- sc->pdom_warp[i].m_recvg_pc = (address_type*)calloc(warp_size * 2, sizeof(address_type));
- sc->pdom_warp[i].m_branch_div_cycle = (unsigned long long *)calloc(warp_size * 2, sizeof(unsigned long long ));
-
- memset(sc->pdom_warp[i].m_pc, -1, warp_size * 2 * sizeof(address_type));
- memset(sc->pdom_warp[i].m_calldepth, 0, warp_size * 2 * sizeof(unsigned int));
- memset(sc->pdom_warp[i].m_active_mask, 0, warp_size * 2 * sizeof(unsigned int));
- memset(sc->pdom_warp[i].m_recvg_pc, -1, warp_size * 2 * sizeof(address_type));
- }
+ snprintf(L1I_name, STRSIZE, "L1I_%03d", m_sid);
+ m_L1I = shd_cache_create(L1I_name,m_config->gpgpu_cache_il1_opt,1,0, no_writes );
+ shd_cache_bind_logger(m_L1D, m_sid, get_shader_instruction_cache_id());
- sc->waiting_at_barrier = 0;
+ m_mshr_unit = new mshr_shader_unit(m_config);
+ 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;
- sc->last_issued_thread = sc->n_threads - 1;
-
- sc->using_dwf = (sc->model == DWF);
-
- sc->using_rrstage = (sc->model == DWF);
-
- sc->using_commit_queue = (sc->model == DWF
- || sc->model == POST_DOMINATOR || sc->model == NO_RECONVERGE);
+ // Initialize scoreboard
+ m_scoreboard = new Scoreboard(m_sid, m_config->max_warps_per_shader);
- if (sc->using_commit_queue) {
- sc->thd_commit_queue = dq_create("thd_commit_queue", 0, 0, 0);
+ if( m_config->gpgpu_operand_collector ) {
+ m_operand_collector.init( m_config->gpgpu_operand_collector_num_units,
+ m_config->gpgpu_operand_collector_num_units_sfu,
+ m_config->gpgpu_num_reg_banks, this,
+ &m_pipeline_reg[ID_EX],
+ &m_pipeline_reg[OC_EX_SFU] );
}
- sc->shmem_size = gpgpu_shmem_size;
- sc->n_registers = gpgpu_shader_registers;
- sc->n_cta = gpgpu_shader_cta;
+ m_memory_queue.shared.reserve(warp_size);
+ m_memory_queue.constant.reserve(warp_size);
+ m_memory_queue.texture.reserve(warp_size);
+ m_memory_queue.local_global.reserve(warp_size);
- sc->shader_memory_new_instruction_processed = false;
+ // writeback
+ m_pl_tid = (int*) malloc(sizeof(int)*warp_size);
+ m_mshr_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * warp_size);
+ m_pl_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * warp_size);
- // Initialize scoreboard
- sc->scrb = new Scoreboard(sc->sid, n_warp);
+ // 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
- if( gpgpu_operand_collector ) {
- m_opndcoll_new.init( gpgpu_operand_collector_num_units,
- gpgpu_operand_collector_num_units_sfu,
- gpgpu_num_reg_banks, this );
+ 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);
}
-
-unsigned shader_reinit(shader_core_ctx_t *sc, int start_thread, int end_thread )
+void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed )
{
- int i;
- unsigned result=0;
-
- if ( gpgpu_cuda_sim ) {
- unsigned cta_size = ptx_sim_cta_size();
- if ( cta_size > sc->n_threads ) {
- printf("Execution error: Shader kernel CTA (block) size is too large for microarch config.\n");
- printf(" This can cause problems with applications that use __syncthreads.\n");
- printf(" CTA size (x*y*z) = %u, n_threads = %u\n", cta_size, sc->n_threads );
- printf(" => either change -gpgpu_shader argument in gpgpusim.config file or\n");
- printf(" modify the CUDA source to decrease the kernel block size.\n");
- abort();
- }
+ 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;
}
-
- sc->next_warp = 0;
- sc->branch_priority = 0;
-
- for (i = start_thread; i<end_thread; i++)
- ptx_sim_free_sm(&sc->thread[i].ptx_thd_info);
-
- for (i = start_thread; i<end_thread; i++) {
- sc->max_branch_priority[i] = INT_MAX;
- sc->thread[i].warp_priority = sc->max_branch_priority[i];
- sc->thread[i].n_insn = 0;
- sc->thread[i].cta_id = -1;
+ for (unsigned i = start_thread / m_config->warp_size; i < end_thread / m_config->warp_size; ++i) {
+ m_warp[i].reset();
+ m_pdom_warp[i]->reset();
}
-
- for (unsigned i = start_thread / warp_size; i < end_thread / warp_size; ++i) {
- sc->warp[i].reset(warp_size);
- sc->pdom_warp[i].m_stack_top = 0;
- memset(sc->pdom_warp[i].m_pc, -1, warp_size * 2 * sizeof(address_type));
- memset(sc->pdom_warp[i].m_calldepth, 0, warp_size * 2 * sizeof(unsigned int));
- memset(sc->pdom_warp[i].m_active_mask, 0, warp_size * 2 * sizeof(unsigned int));
- memset(sc->pdom_warp[i].m_recvg_pc, -1, warp_size * 2 * sizeof(address_type));
- memset(sc->pdom_warp[i].m_branch_div_cycle, 0, warp_size * 2 * sizeof(unsigned long long ));
- }
-
- sc->waiting_at_barrier = 0;
- sc->last_issued_thread = end_thread - 1;
-
- if (sc->using_commit_queue) {
- if (!gpgpu_spread_blocks_across_cores) //assertion no longer holds with multiple blocks per core
- assert(dq_empty(sc->thd_commit_queue));
- }
- sc->pending_shmem_bkacc = 0;
- sc->pending_cache_bkacc = 0;
- sc->pending_cmem_acc = 0;
-
- //do not reset this here, shader memory may be in the middle of processing another cta's instruction.
- //sc->shader_memory_new_instruction_processed = false;
-
- return result;
}
-// initialize a CTA in the shader core, currently only useful for PDOM and DWF
-
-void shader_init_CTA(shader_core_ctx_t *shader, int start_thread, int end_thread)
+void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread )
{
- int i;
- int n_thread = end_thread - start_thread;
- address_type start_pc = ptx_thread_get_next_pc(shader->thread[start_thread].ptx_thd_info);
- if (shader->model == POST_DOMINATOR) {
- int start_warp = start_thread / warp_size;
- int end_warp = end_thread / warp_size + ((end_thread % warp_size)? 1 : 0);
- for (i = start_warp; i < end_warp; ++i) {
- shader->pdom_warp[i].m_stack_top = 0;
- memset(shader->pdom_warp[i].m_pc, -1, warp_size * 2 * sizeof(address_type));
- memset(shader->pdom_warp[i].m_calldepth, 0, warp_size * 2 * sizeof(unsigned int));
- memset(shader->pdom_warp[i].m_active_mask, 0, warp_size * 2 * sizeof(unsigned int));
- memset(shader->pdom_warp[i].m_recvg_pc, -1, warp_size * 2 * sizeof(address_type));
- memset(shader->pdom_warp[i].m_branch_div_cycle, 0, warp_size * 2 * sizeof(unsigned long long ));
- shader->pdom_warp[i].m_pc[0] = start_pc;
- shader->pdom_warp[i].m_calldepth[0] = 1;
- int t = 0;
- for (t = 0; t < (int)warp_size; t++) {
- if ( i * (int)warp_size + t < end_thread ) {
- shader->pdom_warp[i].m_active_mask[0] |= (1 << t);
+ 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;
+ unsigned end_warp = end_thread / m_config->warp_size + ((end_thread % m_config->warp_size)? 1 : 0);
+ for (unsigned i = start_warp; i < end_warp; ++i) {
+ unsigned initial_active_mask = 0;
+ unsigned n_active=0;
+ for (unsigned t = 0; t < m_config->warp_size; t++) {
+ if ( i * m_config->warp_size + t < end_thread ) {
+ initial_active_mask |= (1 << t);
+ n_active++;
+ }
}
- }
+ m_pdom_warp[i]->launch(start_pc,initial_active_mask);
+ m_warp[i].init(start_pc,i,n_active);
+ m_not_completed += n_active;
}
- } else if (shader->model == DWF) {
- dwf_init_CTA(shader->sid, start_thread, n_thread, start_pc);
+ } 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;
}
-
- for (i = start_thread; i<end_thread; i++) {
- shader->thread[i].in_scheduler = 1;
- }
}
-
-
-
// register id for unused register slot in instruction
#define DNA (0)
unsigned g_next_shader_inst_uid=1;
-// check to see if the fetch stage need to be stalled
-int shader_fetch_stalled(shader_core_ctx_t *shader)
+bool shader_core_ctx::fetch_stalled()
{
- int n_warp_parts = warp_size/pipe_simd_width;
-
- if (shader->warp_part2issue < n_warp_parts) {
- return 1;
- }
-
- for (unsigned i=0; i<warp_size; i++) {
- if (shader->pipeline_reg[TS_IF][i].hw_thread_id != -1 ) {
- return 1; // 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 (int i=0; i<pipe_simd_width; i++) {
- if (shader->pipeline_reg[IF_ID][i].hw_thread_id != -1 ) {
- return 1; // 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
}
}
- shader->warp_part2issue = 0; // reset pointer to first warp part
- shader->new_warp_TS = 1;
-
- return 0; // not stalled
+ m_new_warp_TS = true;
+ return false; // not stalled
}
// initalize the pipeline stage register to nops
-void shader_clear_stage_reg(shader_core_ctx_t *shader, int stage)
+void shader_core_ctx::clear_stage_reg(int stage)
{
- for (unsigned i=0; i<warp_size; i++) {
- shader->pipeline_reg[stage][i] = nop_inst;
- }
+ clear_stage( m_pipeline_reg[stage] );
}
// return the next pc of a thread
-address_type shader_thread_nextpc(shader_core_ctx_t *shader, int tid)
+address_type shader_core_ctx::next_pc( int tid ) const
{
- assert( gpgpu_cuda_sim );
- address_type pc = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info );
- return pc;
+ if( tid == -1 )
+ return -1;
+ ptx_thread_info *the_thread = m_thread[tid].m_functional_model_thread_state;
+ if ( the_thread == NULL )
+ return -1;
+ 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_issue_thread(shader_core_ctx_t *shader, int tid, int wlane, unsigned active_mask )
-{
- if ( gpgpu_cuda_sim ) {
- shader->pipeline_reg[TS_IF][wlane].hw_thread_id = tid;
- shader->pipeline_reg[TS_IF][wlane].wlane = wlane;
- shader->pipeline_reg[TS_IF][wlane].pc = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info );
- shader->pipeline_reg[TS_IF][wlane].ptx_thd_info = shader->thread[tid].ptx_thd_info;
- shader->pipeline_reg[TS_IF][wlane].memreqaddr = 0;
- shader->pipeline_reg[TS_IF][wlane].reg_bank_conflict_stall_checked = 0;
- shader->pipeline_reg[TS_IF][wlane].reg_bank_access_pending = 0;
- shader->pipeline_reg[TS_IF][wlane].uid = g_next_shader_inst_uid++;
- shader->pipeline_reg[TS_IF][wlane].warp_active_mask = active_mask;
- shader->pipeline_reg[TS_IF][wlane].ts_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
- }
- assert( shader->thread[tid].avail4fetch > 0 );
- shader->thread[tid].avail4fetch--;
- assert( shader->warp[wid_from_hw_tid(tid,warp_size)].n_avail4fetch > 0 );
- shader->warp[wid_from_hw_tid(tid,warp_size)].n_avail4fetch--;
-}
-
-void update_max_branch_priority(shader_core_ctx_t *shader, unsigned warp_hw_id, unsigned grid_num )
+void shader_core_ctx::shader_issue_thread(int tid, int wlane, unsigned active_mask )
{
- int temp_max = 0;
- // This means that a group of threads has completed,
- // hence need to update max_priority
- for (unsigned i = 0; i<warp_size; i++) {
- if ( !ptx_thread_done( shader->thread[hw_tid_from_wid(warp_hw_id,warp_size,i)].ptx_thd_info ) ) {
- if (shader->thread[hw_tid_from_wid(warp_hw_id,warp_size,i)].warp_priority>=temp_max) {
- temp_max = shader->thread[hw_tid_from_wid(warp_hw_id,warp_size,i)].warp_priority;
- }
- }
- }
- for (unsigned i = 0; i<warp_size; i++) {
- shader->max_branch_priority[hw_tid_from_wid(warp_hw_id,warp_size,i)] = temp_max;
- }
-}
-
-void shader_fetch_simd_no_reconverge(shader_core_ctx_t *shader, unsigned int shader_number, int grid_num )
-{
- int i;
- int tid;
- int new_tid = 0;
- address_type pc = 0;
- int warp_ok = 0;
- int n_warp = shader->n_threads/warp_size;
- int complete = 0;
-
- assert(gpgpu_cuda_sim);
-
- // First, check to see if entire program is completed,
- // if it is, then break out of loop
- for (unsigned i=0; i<shader->n_threads; i++) {
- if (!ptx_thread_done( shader->thread[i].ptx_thd_info )) {
- complete = 0;
- break;
- } else {
- complete = 1;
- }
- }
- if (complete) {
- // printf("Shader has completed program.\n");
- return;
- }
-
- if (shader_fetch_stalled(shader)) {
- return;
- }
- shader_clear_stage_reg(shader, TS_IF);
-
- // 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 (i=0; i<n_warp; i++) {
- int n_completed = shader->warp[shader->next_warp].n_completed;
- int n_avail4fetch = shader->warp[shader->next_warp].n_avail4fetch;
- if (((n_completed) == (int)warp_size) ||
- ((n_completed + n_avail4fetch) < (int)warp_size) ) {
- //All threads in this warp have completed, hence go to next warp
- //Or, some of the threads are still in pipeline
- warp_ok = 0; // hey look, it's a silent register update / store instruction! (this operation is redundant)
- shader->next_warp = (shader->next_warp+1)%n_warp;
- } else {
- int n_waiting_at_barrier = shader->warp[shader->next_warp].n_waiting_at_barrier;
- if ( n_waiting_at_barrier >= (int)warp_size ) {
- warp_ok = 0; // hey look, it's a silent register update / store instruction! (this operation is redundant)
- continue;
- }
- warp_ok = 1;
- break;
- }
- }
- // None of the instructions from inside the warp can be scheduled -> should
- // probably just stall, ie nops into pipeline
- if (!warp_ok) {
- shader_clear_stage_reg(shader, TS_IF); // NOTE: is this needed?
- shader->next_warp = (shader->next_warp+1)%n_warp; // NOTE: this is not round-robin.
- return;
- }
-
- tid = warp_size*shader->next_warp;
-
- for (i = 0; i<(int)warp_size; i++) {
- if (shader->thread[tid+i].warp_priority == shader->max_branch_priority[tid+i]) {
- pc = shader_thread_nextpc(shader, tid+i);
- new_tid = tid+i;
- break;
- }
- }
- //Determine which instructions inside this 'warp' will be scheduled together at this run
- //If they are cannot be scheduled together then 'save' their branch priority
- for (i = 0; i<(int)warp_size; i++) {
- if (!ptx_thread_done( shader->thread[tid+i].ptx_thd_info )) {
- address_type next_pc;
- next_pc = shader_thread_nextpc(shader, tid+i);
- if (next_pc != pc ||
- shader->thread[tid+i].warp_priority != shader->max_branch_priority[tid+i] ||
- shader->thread[tid+i].m_waiting_at_barrier) {
- if (!ptx_thread_done( shader->thread[tid+i].ptx_thd_info )) {
- if ( !shader->thread[tid + i].m_waiting_at_barrier ) {
- shader->thread[tid + i].warp_priority = shader->branch_priority;
- }
- }
- } else {
- shader_issue_thread(shader, tid+i, i,(unsigned)-1);
- }
- }
- }
- shader->branch_priority++;
+ 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;
- shader->next_warp = (shader->next_warp+1)%n_warp;
+ 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 pdom_sched_find_next_warp (shader_core_ctx_t *shader,int pdom_sched_policy, int* ready_warps
- , int ready_warp_count, int* last_warp, int w_comp_c, int w_pipe_c, int w_barr_c)
+int shader_core_ctx::pdom_sched_find_next_warp (int ready_warp_count)
{
- int n_warp = shader->n_threads/warp_size;
- int i=0;
- int selected_warp = ready_warps[0];
- int found =0;
-
- switch (pdom_sched_policy) {
- case 0:
- selected_warp = ready_warps[0]; //first ok warp found
- found=1;
- break;
- case 1 ://random
- selected_warp = ready_warps[rand()%ready_warp_count];
- found=1;
- break;
- case 8 :// execute the first available warp which is after the warp execued last time
- found=0;
- selected_warp = (last_warp[shader->sid] + 1 ) % n_warp;
+ 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 (i=0;i<ready_warp_count;i++) {
- if (selected_warp==ready_warps[i]) {
- found=1;
- }
+ 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 ) % n_warp;
+ if( !found )
+ selected_warp = (selected_warp + 1) % m_config->max_warps_per_shader;
}
break;
- default:
- assert(0);
+ default: assert(0);
}
if (found) {
- if (ready_warp_count==1) {
- n_pdom_sc_single_stat++;
- } else {
- n_pdom_sc_orig_stat++;
- }
+ 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_fetch_simd_postdominator(shader_core_ctx_t *shader, unsigned int shader_number, int grid_num) {
- int i;
+void shader_core_ctx::fetch_simd_postdominator()
+{
int warp_ok = 0;
- int n_warp = shader->n_threads/warp_size;
- int complete = 0;
+ bool complete = false;
int tmp_warp;
int warp_id;
address_type check_pc = -1;
- assert(gpgpu_cuda_sim);
-
// First, check to see if entire program is completed,
// if it is, then break out of loop
- for (unsigned i=0; i<shader->n_threads; i++) {
- if (!ptx_thread_done( shader->thread[i].ptx_thd_info )) {
- complete = 0;
+ for (unsigned i=0; i<m_config->n_thread_per_shader; i++) {
+ if (!ptx_thread_done(i)) {
+ complete = false;
break;
} else {
- complete = 1;
+ complete = true;
}
}
- if (complete) {
+ if (complete)
return;
- }
- if (shader_fetch_stalled(shader)) {
+ if (fetch_stalled())
return;
- }
- shader_clear_stage_reg(shader, TS_IF);
-
- int ready_warp_count = 0;
- int w_comp_c = 0 ;
- int w_pipe_c = 0 ;
- int w_barr_c = 0 ;
- static int * ready_warps = NULL;
- static int * tmp_ready_warps = NULL;
- if (!ready_warps) {
- ready_warps = (int*)calloc(n_warp,sizeof(int));
- }
- if (!tmp_ready_warps) {
- tmp_ready_warps = (int*)calloc(n_warp,sizeof(int));
- }
- for (i=0; i<n_warp; i++) {
- ready_warps[i]=-1;
- tmp_ready_warps[i]=-1;
- }
+ clear_stage_reg(TS_IF);
- static int* last_warp; //keeps track of last warp issued per shader
- if (!last_warp) {
- last_warp = (int*)calloc(gpu_n_shader,sizeof(int));
+ 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 (i=0; i<n_warp; i++) {
- int n_completed = shader->warp[shader->next_warp].n_completed;
- int n_avail4fetch = shader->warp[shader->next_warp].n_avail4fetch;
-
- if ((n_completed) == (int)warp_size) {
- //All threads in this warp have completed
- w_comp_c++;
- } else if ((n_completed+n_avail4fetch) < (int)warp_size) {
- //some of the threads are still in pipeline
- w_pipe_c++;
- } else if ( shader->warp_waiting_at_barrier(shader->next_warp) ) {
- w_barr_c++;
- } else if ( shader_warp_scoreboard_hazard(shader, shader->next_warp) ) {
- // Do nothing - warp is filtered out
- //printf("SCOREBOARD COLLISION - wid=%d\n", shader->next_warp);
- } else {
- // A valid warp is found at this point
- tmp_ready_warps[ready_warp_count] = shader->next_warp;
- ready_warp_count++;
+ 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++;
}
- shader->next_warp = (shader->next_warp + 1) % n_warp;
- }
- for (i=0;i<ready_warp_count;i++) {
- ready_warps[i]=tmp_ready_warps[i];
+ m_next_warp = (m_next_warp + 1) % m_config->max_warps_per_shader;
}
-
- num_warps_issuable[ready_warp_count]++;
- num_warps_issuable_pershader[shader->sid]+= ready_warp_count;
-
+ 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 (shader, pdom_sched_type ,ready_warps
- , ready_warp_count, last_warp, w_comp_c, w_pipe_c ,w_barr_c);
+ tmp_warp = pdom_sched_find_next_warp (ready_warp_count);
if (tmp_warp != -1) {
- shader->next_warp = tmp_warp;
+ m_next_warp = tmp_warp;
warp_ok=1;
}
}
- static int no_warp_issued;
- // None of the instructions from inside the warp can be scheduled -> should
- // probably just stall, ie nops into pipeline
if (!warp_ok) {
- shader_clear_stage_reg(shader, TS_IF);
- shader->next_warp = (shader->next_warp+1) % n_warp;
- no_warp_issued = 1 ;
+ // 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
- //shader->next_warp
-
- warp_id = shader->next_warp;
- last_warp[shader->sid] = warp_id;
- int wtid = warp_size*warp_id;
+ // at this point we have a warp to execute which is pointed to by next_warp
- pdom_warp_ctx_t *scheduled_warp = &(shader->pdom_warp[warp_id]);
+ 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
- for (i = 0; i < (int)warp_size; i++) {
+ unsigned active_mask = scheduled_warp->get_active_mask();
+
+ for (unsigned i = 0; i < m_config->warp_size; i++) {
unsigned int mask = (1 << i);
- if ((scheduled_warp->m_active_mask[scheduled_warp->m_stack_top] & mask) == mask) {
- assert (!ptx_thread_done( shader->thread[wtid+i].ptx_thd_info ));
- shader_issue_thread(shader, wtid+i, i, scheduled_warp->m_active_mask[scheduled_warp->m_stack_top]);
+ if ((active_mask & mask) == mask) {
+ assert (!ptx_thread_done(wtid+i));
+ shader_issue_thread(wtid+i,i,active_mask);
}
}
- shader->next_warp = (shader->next_warp+1)%n_warp;
+ m_next_warp = (m_next_warp+1)%m_config->max_warps_per_shader;
// check if all issued threads have the same pc
- for (i = 0; i < (int) warp_size; i++) {
- if ( shader->pipeline_reg[TS_IF][i].hw_thread_id != -1 ) {
+ 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 = shader->pipeline_reg[TS_IF][i].pc;
+ check_pc = m_pipeline_reg[TS_IF][i].pc;
} else {
- assert( check_pc == shader->pipeline_reg[TS_IF][i].pc );
+ assert( check_pc == m_pipeline_reg[TS_IF][i].pc );
}
}
}
}
-bool shader_warp_scoreboard_hazard(shader_core_ctx_t *shader, int warp_id) {
- static inst_t active_inst;
- static op_type op = NO_OP;
- static int i1, i2, i3, i4, o1, o2, o3, o4; //4 outputs needed for texture fetches in cuda-sim
- static int vectorin, vectorout;
- static int arch_reg[MAX_REG_OPERANDS] = { -1 };
- static int pred;
- static int ar1, ar2; // address registers for memory operands
+/**
+ * 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 = warp_size*warp_id;
- pdom_warp_ctx_t *scheduled_warp = &(shader->pdom_warp[warp_id]);
+ 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;
- for (int i = 0; i < (int)warp_size; i++) {
+ unsigned active_mask = scheduled_warp->get_active_mask();
+ for (unsigned i = 0; i < m_config->warp_size; i++) {
unsigned int mask = (1 << i);
- if ((scheduled_warp->m_active_mask[scheduled_warp->m_stack_top] & mask) == mask) {
- active_thread = &(shader->thread[wtid+i]);
+ if ((active_mask & mask) == mask) {
+ active_thread = &(m_thread[wtid+i]);
}
}
- if(active_thread == NULL) return false;
+ if(active_thread == NULL)
+ return false;
// Decode instruction
- ptx_decode_inst( active_thread->ptx_thd_info, (unsigned*)&op, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg, &pred, &ar1, &ar2);
- active_inst.op = op;
- active_inst.in[0] = i1;
- active_inst.in[1] = i2;
- active_inst.in[2] = i3;
- active_inst.in[3] = i4;
- active_inst.out[0] = o1;
- active_inst.out[1] = o2;
- active_inst.out[2] = o3;
- active_inst.out[3] = o4;
- active_inst.is_vectorin = vectorin;
- active_inst.is_vectorout = vectorout;
- active_inst.pred = pred;
- active_inst.ar1 = ar1;
- active_inst.ar2 = ar2;
-
- return shader->scrb->checkCollision(warp_id, &active_inst);
+ active_thread->m_functional_model_thread_state->ptx_fetch_inst( active_inst );
+ return m_scoreboard->checkCollision(warp_id, &active_inst);
}
-void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id) {
- int wtid = warp_size*warp_id;
+void pdom_warp_ctx_t::pdom_update_warp_mask()
+{
+ int wtid = m_warp_size*m_warp_id;
- pdom_warp_ctx_t *scheduled_warp = &(shader->pdom_warp[warp_id]);
+ pdom_warp_ctx_t *scheduled_warp = this;
int stack_top = scheduled_warp->m_stack_top;
@@ -1176,21 +788,21 @@ void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id) {
// extract a group of threads with the same next PC among the active threads in the warp
address_type tmp_next_pc = null_pc;
unsigned int tmp_active_mask = 0;
- void *first_active_thread=NULL;
- for (int i = warp_size - 1; i >= 0; i--) {
+ class ptx_thread_info *first_active_thread=NULL;
+ for (int i = m_warp_size - 1; i >= 0; i--) {
unsigned int mask = (1 << i);
if ((top_active_mask & mask) == mask) { // is this thread active?
- if (ptx_thread_done( shader->thread[wtid+i].ptx_thd_info )) {
- top_active_mask &= ~mask; // remove completed thread from active mask
- } else if (tmp_next_pc == null_pc) {
- first_active_thread = shader->thread[wtid+i].ptx_thd_info;
- tmp_next_pc = shader_thread_nextpc(shader, wtid+i);
- tmp_active_mask |= mask;
- top_active_mask &= ~mask;
- } else if (tmp_next_pc == shader_thread_nextpc(shader, wtid+i)) {
- tmp_active_mask |= mask;
- top_active_mask &= ~mask;
- }
+ if (m_shader->ptx_thread_done(wtid+i)) {
+ top_active_mask &= ~mask; // remove completed thread from active mask
+ } else if (tmp_next_pc == null_pc) {
+ first_active_thread=m_shader->get_thread_state(wtid+i);
+ tmp_next_pc = first_active_thread->get_pc();
+ tmp_active_mask |= mask;
+ top_active_mask &= ~mask;
+ } else if (tmp_next_pc == m_shader->get_thread_state(wtid+i)->get_pc()) {
+ tmp_active_mask |= mask;
+ top_active_mask &= ~mask;
+ }
}
}
@@ -1229,60 +841,102 @@ void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id) {
scheduled_warp->m_stack_top = stack_top - 1;
assert(scheduled_warp->m_stack_top >= 0);
- assert(scheduled_warp->m_stack_top < (int)warp_size * 2);
+ assert(scheduled_warp->m_stack_top < m_warp_size * 2);
+}
+
+void gpgpu_sim::get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc )
+{
+ m_sc[sid]->get_pdom_stack_top_info(tid,pc,rpc);
+}
+
+void shader_core_ctx::get_pdom_stack_top_info( unsigned tid, unsigned *pc, unsigned *rpc )
+{
+ unsigned warp_id = tid/m_config->warp_size;
+ m_pdom_warp[warp_id]->get_pdom_stack_top_info(pc,rpc);
}
+void pdom_warp_ctx_t::get_pdom_stack_top_info( unsigned *pc, unsigned *rpc )
+{
+ *pc = m_pc[m_stack_top];
+ *rpc = m_recvg_pc[m_stack_top];
+}
-void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc )
+unsigned pdom_warp_ctx_t::get_rp() const
+{
+ return m_recvg_pc[m_stack_top];
+}
+
+void pdom_warp_ctx_t::print (FILE *fout) const
{
- unsigned warp_id = tid/warp_size;
- pdom_warp_ctx_t *warp_info = &(sc[sid]->pdom_warp[warp_id]);
- unsigned idx = warp_info->m_stack_top;
- *pc = warp_info->m_pc[idx];
- *rpc = warp_info->m_recvg_pc[idx];
+ const pdom_warp_ctx_t *warp=this;
+ for ( unsigned k=0; k <= warp->m_stack_top; k++ ) {
+ if ( k==0 ) {
+ fprintf(fout, "w%02d %1u ", m_warp_id, k );
+ } else {
+ fprintf(fout, " %1u ", k );
+ }
+ for (unsigned m=1,j=0; j<m_warp_size; j++, m<<=1)
+ fprintf(fout, "%c", ((warp->m_active_mask[k] & m)?'1':'0') );
+ fprintf(fout, " pc: %4u", warp->m_pc[k] );
+ if ( warp->m_recvg_pc[k] == (unsigned)-1 ) {
+ fprintf(fout," rp: ---- cd: %2u ", warp->m_calldepth[k] );
+ } else {
+ fprintf(fout," rp: %4u cd: %2u ", warp->m_recvg_pc[k], warp->m_calldepth[k] );
+ }
+ if ( warp->m_branch_div_cycle[k] != 0 ) {
+ fprintf(fout," bd@%6u ", (unsigned) warp->m_branch_div_cycle[k] );
+ } else {
+ fprintf(fout," " );
+ }
+ ptx_print_insn( warp->m_pc[k], fout );
+ fprintf(fout,"\n");
+ }
}
-void shader_fetch_mimd( shader_core_ctx_t *shader, unsigned int shader_number )
+
+void shader_core_ctx::new_cache_window()
{
- unsigned int last_issued_thread = 0;
+ shd_cache_new_window(m_L1D);
+ shd_cache_new_window(m_L1T);
+ shd_cache_new_window(m_L1C);
+}
- if (shader_fetch_stalled(shader)) {
+void shader_core_ctx::fetch_mimd()
+{
+ if (fetch_stalled())
return;
- }
- shader_clear_stage_reg(shader, TS_IF);
+ clear_stage_reg(TS_IF);
- // some form of barrel processing:
- // - checking availability from the thread after the last issued thread
- for (int i=0, j=0;i<(int)shader->n_threads && j< (int) warp_size;i++) {
- int thd_id = (i + shader->last_issued_thread + 1) % shader->n_threads;
- if (shader->thread[thd_id].avail4fetch && !shader->thread[thd_id].m_waiting_at_barrier ) {
- shader_issue_thread(shader, thd_id, j,(unsigned)-1);
- last_issued_thread = thd_id;
+ 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++;
}
}
- shader->last_issued_thread = last_issued_thread;
}
// seperate the incoming warp into multiple warps with seperate pcs
-int split_warp_by_pc(int *tid_in, shader_core_ctx_t *shader, int **tid_split, address_type *pc) {
+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)*warp_size);
+ memset(pc,0,sizeof(address_type)*m_config->warp_size);
- if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*warp_size);
- memset(pc_cnt,0,sizeof(int)*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< warp_size; i++) {
+ 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 = shader_thread_nextpc(shader, tid_in[i]);
+ thd_pc = next_pc(tid_in[i]);
// check to see if the pc has occured before
for (unsigned j=0; j<n_pc; j++) {
@@ -1295,7 +949,7 @@ int split_warp_by_pc(int *tid_in, shader_core_ctx_t *shader, int **tid_split, ad
}
// if not, put the tid in a seperate warp
if (!matched) {
- assert(n_pc < warp_size);
+ 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;
@@ -1306,12 +960,12 @@ int split_warp_by_pc(int *tid_in, shader_core_ctx_t *shader, int **tid_split, ad
}
// see if this warp just executed the barrier instruction
-int warp_reached_barrier(int *tid_in, shader_core_ctx_t *shader)
+int shader_core_ctx::warp_reached_barrier(int *tid_in)
{
int reached_barrier = 0;
- for (unsigned i=0; i<warp_size; i++) {
+ for (unsigned i=0; i<m_config->warp_size; i++) {
if (tid_in[i] < 0) continue;
- if (shader->thread[tid_in[i]].m_reached_barrier) {
+ if (m_thread[tid_in[i]].m_reached_barrier) {
reached_barrier = 1;
break;
}
@@ -1320,26 +974,27 @@ int warp_reached_barrier(int *tid_in, shader_core_ctx_t *shader)
}
// seperate the incoming warp into multiple warps with seperate pcs and cta
-int split_warp_by_cta(int *tid_in, shader_core_ctx_t *shader, int **tid_split, address_type *pc, int *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)*warp_size);
+ memset(pc,0,sizeof(address_type)*m_config->warp_size);
- if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*warp_size);
- memset(pc_cnt,0,sizeof(int)*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<warp_size; i++) {
+ 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 = shader_thread_nextpc(shader, tid_in[i]);
+ thd_pc = next_pc(tid_in[i]);
- int thd_cta = ptx_thread_get_cta_uid( shader->thread[tid_in[i]].ptx_thd_info );
+ 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++) {
@@ -1352,7 +1007,7 @@ int split_warp_by_cta(int *tid_in, shader_core_ctx_t *shader, int **tid_split, a
}
// if not, put the tid in a seperate warp
if (!matched) {
- assert(n_pc < warp_size);
+ 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;
@@ -1363,638 +1018,508 @@ int split_warp_by_cta(int *tid_in, shader_core_ctx_t *shader, int **tid_split, a
return n_pc;
}
-void shader_fetch_simd_dwf( shader_core_ctx_t *shader, unsigned int shader_number ) {
-
+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)*warp_size);
- memset(tid_in, -1, sizeof(int)*warp_size);
+ 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)*warp_size);
- memset(tid_out, -1, sizeof(int)*warp_size);
+ 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*)*warp_size);
- tid_split[0] = (int*)malloc(sizeof(int)*warp_size*warp_size);
- for (unsigned i=1; i<warp_size; i++) {
- tid_split[i] = tid_split[0] + warp_size * i;
+ 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)*warp_size);
+ 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)*warp_size);
+ if (!thd_cta) thd_cta = (int*)malloc(sizeof(int)*m_config->warp_size);
int warpupdate_bw = 1;
- while (!dq_empty(shader->thd_commit_queue) && warpupdate_bw > 0) {
+ while (!m_thd_commit_queue->empty() && warpupdate_bw > 0) {
// grab a committed warp, split it into multiple BRUs (tid_split) by PC
- int *tid_commit = (int*)dq_pop(shader->thd_commit_queue);
- memset(tid_split[0], -1, sizeof(int)*warp_size*warp_size);
- memset(thd_pc, 0, sizeof(address_type)*warp_size);
- memset(thd_cta, -1, sizeof(int)*warp_size);
+ 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, shader);
+ 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, shader, tid_split, thd_pc, thd_cta);
+ 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, shader, tid_split, thd_pc);
+ n_warp_update = split_warp_by_pc(tid_commit->data(), tid_split, thd_pc);
}
- if (n_warp_update > 2) gpgpu_commit_pc_beyond_two++;
+ 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<warp_size;j++) {
+ for (unsigned j=0;j<m_config->warp_size;j++) {
if (tid_split[i][j] < 0) continue;
- assert(shader->thread[tid_split[i][j]].avail4fetch);
- assert(!shader->thread[tid_split[i][j]].in_scheduler);
- shader->thread[tid_split[i][j]].in_scheduler = 1;
+ 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(shader->sid);
+ dwf_clear_accessed(m_sid);
if (reached_barrier) {
- dwf_update_warp_at_barrier(shader->sid, tid_split[i], thd_pc[i], thd_cta[i]);
+ dwf_update_warp_at_barrier(m_sid, tid_split[i], thd_pc[i], thd_cta[i]);
} else {
- dwf_update_warp(shader->sid, tid_split[i], thd_pc[i]);
+ dwf_update_warp(m_sid, tid_split[i], thd_pc[i]);
}
}
- free_commit_warp(tid_commit);
+ delete tid_commit;
}
// Track the #PC right after the warps are input to the scheduler
- dwf_update_statistics(shader->sid);
- dwf_clear_policy_access(shader->sid);
+ dwf_update_statistics(m_sid);
+ dwf_clear_policy_access(m_sid);
- if (shader_fetch_stalled(shader)) {
+ if (fetch_stalled()) {
return;
}
- shader_clear_stage_reg(shader, TS_IF);
+ clear_stage_reg(TS_IF);
address_type scheduled_pc;
- dwf_issue_warp(shader->sid, tid_out, &scheduled_pc);
+ dwf_issue_warp(m_sid, tid_out, &scheduled_pc);
- for (unsigned i=0; i<warp_size; i++) {
+ for (unsigned i=0; i<m_config->warp_size; i++) {
int issue_tid = tid_out[i];
if (issue_tid >= 0) {
- shader_issue_thread(shader, issue_tid, i, (unsigned)-1);
- shader->thread[issue_tid].in_scheduler = 0;
- shader->thread[issue_tid].m_reached_barrier = 0;
- shader->last_issued_thread = issue_tid;
- assert(shader->pipeline_reg[TS_IF][i].pc == scheduled_pc);
+ 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 print_shader_cycle_distro( FILE *fout )
+void gpgpu_sim::print_shader_cycle_distro( FILE *fout ) const
{
fprintf(fout, "Warp Occupancy Distribution:\n");
- fprintf(fout, "Stall:%d\t", shader_cycle_distro[0]);
- fprintf(fout, "W0_Idle:%d\t", shader_cycle_distro[1]);
- fprintf(fout, "W0_Mem:%d", shader_cycle_distro[2]);
- for (unsigned i = 3; i < warp_size + 3; i++) {
- fprintf(fout, "\tW%d:%d", i-2, shader_cycle_distro[i]);
+ fprintf(fout, "Stall:%d\t", m_shader_stats->shader_cycle_distro[0]);
+ fprintf(fout, "W0_Idle:%d\t", m_shader_stats->shader_cycle_distro[1]);
+ fprintf(fout, "W0_Mem:%d", m_shader_stats->shader_cycle_distro[2]);
+ for (unsigned i = 3; i < m_shader_config->warp_size + 3; i++) {
+ fprintf(fout, "\tW%d:%d", i-2, m_shader_stats->shader_cycle_distro[i]);
}
fprintf(fout, "\n");
}
-void inflight_memory_insn_add( shader_core_ctx_t *shader, inst_t *mem_insn)
+
+#define PROGRAM_MEM_START 0xF0000000 /* should be distinct from other memory spaces...
+ check ptx_ir.h to verify this does not overlap
+ other memory spaces */
+void shader_core_ctx::fetch_new()
{
- if (enable_ptx_file_line_stats) {
- ptx_file_line_stats_add_inflight_memory_insn(shader->sid, mem_insn->pc);
- }
+ 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);
+ 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);
+ 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();
+ }
+ m_inst_fetch_buffer.m_valid = false;
+ }
+
+ if( !m_inst_fetch_buffer.m_valid ) {
+ // find an active warp with space in instruction buffer that is not already waiting on a cache miss
+ // and get next 1-2 instructions from i-cache...
+ for( unsigned i=0; i < m_config->max_warps_per_shader; i++ ) {
+ unsigned warp_id = (m_last_warp_fetched+1+i) % m_config->max_warps_per_shader;
+ if( m_warp[warp_id].done() && !m_scoreboard->pendingWrites(warp_id) && !m_warp[warp_id].done_exit()
+ && m_warp[warp_id].stores_done() && !m_warp[warp_id].inst_in_pipeline() ) {
+ bool did_exit=false;
+ for( unsigned t=0; t<m_config->warp_size;t++) {
+ unsigned tid=warp_id*m_config->warp_size+t;
+ if( m_thread[tid].m_functional_model_thread_state ) {
+ register_cta_thread_exit(tid);
+ m_not_completed -= 1;
+ m_thread[tid].m_functional_model_thread_state=NULL;
+ did_exit=true;
+ }
+ }
+ if( did_exit )
+ m_warp[warp_id].set_done_exit();
+ }
+ if( !m_warp[warp_id].done() && !m_warp[warp_id].imiss_pending() && m_warp[warp_id].ibuffer_empty() ) {
+ address_type pc = m_warp[warp_id].get_pc();
+ address_type ppc = pc + PROGRAM_MEM_START;
+ address_type wb=0;
+ unsigned nbytes=16;
+ unsigned offset_in_block = pc & (m_L1I->line_sz-1);
+ if( (offset_in_block+nbytes) > m_L1I->line_sz )
+ nbytes = (m_L1I->line_sz-offset_in_block);
+ enum cache_request_status status = shd_cache_access_new( m_L1I, (unsigned long long)pc, nbytes, 0, gpu_sim_cycle, &wb );
+ if( status != HIT ) {
+ unsigned req_size = READ_PACKET_SIZE;
+ if( m_gpu->fq_has_buffer(ppc, req_size, false, m_sid) ) {
+ m_last_warp_fetched=warp_id;
+ mshr_entry *mshr = new mshr_entry();
+ mshr->init(ppc,false,instruction_space,warp_id);
+ fq_push( pc, req_size, false,
+ NO_PARTIAL_WRITE,
+ warp_id,
+ mshr, 0,
+ INST_ACC_R, pc );
+ m_warp[warp_id].set_imiss_pending(mshr);
+ m_warp[warp_id].set_last_fetch(gpu_sim_cycle);
+ }
+ } else {
+ m_last_warp_fetched=warp_id;
+ m_inst_fetch_buffer = ifetch_buffer_t(pc,nbytes,warp_id);
+ m_warp[warp_id].set_last_fetch(gpu_sim_cycle);
+ }
+ break;
+ }
+ }
+ }
}
-void inflight_memory_insn_sub( shader_core_ctx_t *shader, inst_t *mem_insn)
+int is_load ( const inst_t &inst )
{
- if (enable_ptx_file_line_stats) {
- ptx_file_line_stats_sub_inflight_memory_insn(shader->sid, mem_insn->pc);
- }
+ return (inst.op == LOAD_OP || inst.memory_op == memory_load);
}
-void report_exposed_memory_latency( shader_core_ctx_t *shader )
+int is_store ( const inst_t &inst )
{
- if (enable_ptx_file_line_stats) {
- ptx_file_line_stats_commit_exposed_latency(shader->sid, 1);
- }
+ return (inst.op == STORE_OP || inst.memory_op == memory_store);
}
-static int gpgpu_warp_occ_detailed = 0;
-static int **warp_occ_detailed = NULL;
-
-void check_stage_pcs( shader_core_ctx_t *shader, unsigned stage );
-void check_pm_stage_pcs( shader_core_ctx_t *shader, unsigned stage );
+int is_const ( memory_space_t space )
+{
+ return((space.get_type() == const_space) || (space == param_space_kernel));
+}
-void shader_fetch( shader_core_ctx_t *shader, unsigned int shader_number, int grid_num )
+int is_local ( memory_space_t space )
{
- assert(shader->model < NUM_SIMD_MODEL);
- int n_warp_parts = warp_size/pipe_simd_width;
+ return (space == local_space) || (space == param_space_local);
+}
- // check if decode stage is stalled
- int decode_stalled = 0;
- for (int i = 0; i < pipe_simd_width; i++) {
- if (shader->pipeline_reg[IF_ID][i].hw_thread_id != -1 )
- decode_stalled = 1;
- }
- if (shader->gpu_cycle % n_warp_parts == 0) {
+void shader_core_ctx::ptx_exec_inst( 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());
+}
- switch (shader->model) {
- case NO_RECONVERGE:
- shader_fetch_simd_no_reconverge(shader, shader_number, grid_num );
- break;
- case POST_DOMINATOR:
- shader_fetch_simd_postdominator(shader, shader_number, grid_num);
- break;
- case MIMD:
- shader_fetch_mimd(shader, shader_number);
- break;
- case DWF:
- shader_fetch_simd_dwf(shader, shader_number);
- break;
- default:
- fprintf(stderr, "Unknown scheduler: %d\n", shader->model);
- assert(0);
- break;
- }
+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 ( ptx_thread_done(tid) ) {
+ m_warp[warp_id].inc_n_completed();
+ m_warp[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 )
+ 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);
- static int *tid_out = NULL;
- if (!tid_out) {
- tid_out = (int*) malloc(sizeof(int) * warp_size);
- }
- memset(tid_out, -1, sizeof(int)*warp_size);
+ /////
+ 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;
+ }
- if (!shader_cycle_distro) {
- shader_cycle_distro = (unsigned int*) calloc(warp_size + 3, sizeof(unsigned int));
- }
+ m_new_warp_TS = false;
- if (gpgpu_no_divg_load && shader->new_warp_TS && !decode_stalled) {
- int n_thd_in_warp = 0;
- address_type pc_out = 0xDEADBEEF;
- for (unsigned i=0; i<warp_size; i++) {
- tid_out[i] = shader->pipeline_reg[TS_IF][i].hw_thread_id;
- if (tid_out[i] >= 0) {
- n_thd_in_warp += 1;
- pc_out = shader->pipeline_reg[TS_IF][i].pc;
+ // 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);
+}
+
+void shader_core_ctx::decode_new()
+{
+ for ( unsigned i=0; i < m_config->max_warps_per_shader; i++ ) {
+ unsigned warp_id = (m_last_warp_issued+1+i) % m_config->max_warps_per_shader;
+ unsigned checked=0;
+ 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();
+ unsigned pc,rpc;
+ m_pdom_warp[warp_id]->get_pdom_stack_top_info(&pc,&rpc);
+ if( pI ) {
+ if( pc != pI->pc ) {
+ // control hazard
+ m_warp[warp_id].set_next_pc(pc);
+ 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);
+ 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);
+ issued++;
+ }
+ }
}
- }
+ m_warp[warp_id].ibuffer_step();
+ checked++;
+ }
+ if ( issued ) {
+ m_last_warp_issued=warp_id;
+ break;
+ }
+ }
+}
+
+void shader_core_ctx::fetch()
+{
+ // check if decode stage is stalled
+ bool decode_stalled = !pipeline_regster_empty( m_pipeline_reg[IF_ID] );
- //wpt_register_warp(tid_out, shader);
- get_warp_tracker_pool().wpt_register_warp(tid_out, shader, pc_out);
+ // 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;
+ }
- if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) {
- track_thread_pc( shader->sid, tid_out, pc_out );
- }
- if (gpgpu_cflog_interval != 0) {
- insn_warp_occ_log( shader->sid, pc_out, n_thd_in_warp);
- shader_warp_occ_log( shader->sid, n_thd_in_warp);
- }
- if ( gpgpu_warpdistro_shader < 0 || shader->sid == gpgpu_warpdistro_shader ) {
- shader_cycle_distro[n_thd_in_warp + 2] += 1;
- if (n_thd_in_warp == 0) {
- if (shader->pending_mem_access == 0) shader_cycle_distro[1]++;
- }
- }
- shader->new_warp_TS = 0;
+ memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size);
- if (enable_ptx_file_line_stats && n_thd_in_warp > 0) {
- //ptx_file_line_stats_add_warp_issued(pc_out);
- //ptx_file_line_stats_add_warp_occ_total(pc_out, n_thd_in_warp);
+ 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;
}
+ }
- if ( gpgpu_warp_occ_detailed &&
- n_thd_in_warp && (shader->model == POST_DOMINATOR) ) {
- int n_warp = gpu_n_thread_per_shader / warp_size;
- if (!warp_occ_detailed) {
- warp_occ_detailed = (int**) malloc(sizeof(int*) * gpu_n_shader * n_warp);
- warp_occ_detailed[0] = (int*) calloc(sizeof(int), gpu_n_shader * n_warp * warp_size);
- for (unsigned i = 0; i < n_warp * gpu_n_shader; i++) {
- warp_occ_detailed[i] = warp_occ_detailed[0] + i * warp_size;
- }
- }
+ m_new_warp_TS = false;
- int wid = -1;
- for (unsigned i=0; i<warp_size; i++) {
- if (tid_out[i] >= 0) wid = tid_out[i] / warp_size;
- }
- assert(wid != -1);
- warp_occ_detailed[shader->sid * n_warp + wid][n_thd_in_warp - 1] += 1;
+ // 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);
- if (shader->sid == 0 && wid == 16 && 0) {
- printf("wtrace[%08x] ", pc_out);
- for (unsigned i=0; i<warp_size; i++) {
- printf("%03d ", tid_out[i]);
- }
- printf("\n");
- }
- }
- } else {
- if ( gpgpu_warpdistro_shader < 0 || shader->sid == gpgpu_warpdistro_shader ) {
- shader_cycle_distro[0] += 1;
- }
+ // 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 < warp_size; i++) {
- int tid_tsif = shader->pipeline_reg[TS_IF][i].hw_thread_id;
- address_type pc_out = shader->pipeline_reg[TS_IF][i].pc;
- cflog_update_thread_pc(shader->sid, tid_tsif, pc_out);
- }
+ 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 < warp_size; i++) {
- if (shader->pipeline_reg[TS_IF][i].hw_thread_id >= 0) {
- TS_stage_empty = 0;
- break;
- }
- }
- if (TS_stage_empty) {
- report_exposed_memory_latency(shader);
+ 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 && shader->warp_part2issue < n_warp_parts) {
- check_stage_pcs(shader,TS_IF);
- for (int i = 0; i < pipe_simd_width; i++) {
- int wlane_idx = shader->warp_part2issue * pipe_simd_width + i;
- shader->pipeline_reg[IF_ID][i] = shader->pipeline_reg[TS_IF][wlane_idx];
- shader->pipeline_reg[IF_ID][i].if_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
- shader->pipeline_reg[TS_IF][wlane_idx] = nop_inst;
- }
- shader->warp_part2issue += 1;
+ 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]);
}
}
-inline int is_load ( op_type op ) {
- return op == LOAD_OP;
-}
-
-inline int is_store ( op_type op ) {
- return op == STORE_OP;
-}
-
-inline int is_tex ( memory_space_t space ) {
- return((space) == tex_space);
-}
-
-inline int is_const ( memory_space_t space ) {
- return((space.get_type() == const_space) || (space == param_space_kernel));
-}
-
-inline int is_local ( memory_space_t space ) {
- return (space == local_space) || (space == param_space_local);
-}
-
-inline int is_param ( memory_space_t space ) {
- return (space == param_space_kernel);
-}
-
-inline int is_shared ( memory_space_t space ) {
- return((space) == shared_space);
-}
-
-inline int shmem_bank ( address_type addr ) {
- return((int)(addr/((address_type)WORD_SIZE)) % gpgpu_n_shmem_bank);
-}
-
-inline int cache_bank ( address_type addr, shader_core_ctx_t *shader ) {
- return(int)( addr >> (address_type)shader->L1cache->line_sz_log2 ) & ( gpgpu_n_cache_bank - 1 );
-}
-
-inline address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes)
+address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes)
{
return (addr >> segment_size_lg2bytes);
}
-
-inline address_type translate_local_memaddr(address_type localaddr, shader_core_ctx_t *shader, int tid)
+address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader )
{
// During functional execution, each thread sees its own memory space for local memory, but these
// need to be mapped to a shared address space for timing simulation. We do that mapping here.
- localaddr -= 0x100;
localaddr /=4;
- if (gpgpu_local_mem_map) {
+ if (m_config->gpgpu_local_mem_map) {
// Dnew = D*nTpC*nCpS*nS + nTpC*C + T%nTpC
// C = S + nS*(T/nTpC)
// D = data index; T = thread; C = CTA; S = shader core; p = per
// keep threads in a warp contiguous
// then distribute across memory space by CTAs from successive shader cores first,
// then by successive CTA in same shader core
- localaddr *= gpu_padded_cta_size * gpu_max_cta_per_shader * gpu_n_shader;
- localaddr += gpu_padded_cta_size * (shader->sid + gpu_n_shader * (tid / gpu_padded_cta_size));
- localaddr += tid % gpu_padded_cta_size;
+ localaddr *= m_config->gpu_padded_cta_size * m_config->gpu_max_cta_per_shader * num_shader;
+ localaddr += m_config->gpu_padded_cta_size * (m_sid + num_shader * (tid / m_config->gpu_padded_cta_size));
+ localaddr += tid % m_config->gpu_padded_cta_size;
} else {
// legacy mapping that maps the same address in the local memory space of all threads
// to a single contiguous address region
- localaddr *= gpu_n_shader * gpu_n_thread_per_shader;
- localaddr += (gpu_n_thread_per_shader*shader->sid) + tid;
+ localaddr *= num_shader * m_config->n_thread_per_shader;
+ localaddr += (m_config->n_thread_per_shader *m_sid) + tid;
}
localaddr *= 4;
- localaddr += 0x100;
return localaddr;
}
/////////////////////////////////////////////////////////////////////////////////////////
-// Register Bank Conflict Structures
-
-bool gpgpu_reg_bank_conflict_model;
-
-#define MAX_REG_BANKS 32
-unsigned int gpgpu_num_reg_banks; // this needs to be less than MAX_REG_BANKS
-bool gpgpu_reg_bank_use_warp_id;
-
-#define MAX_BANK_CONFLICT 8 /* tex can have four source and four destination regs */
-
-class reg_bank_access {
-public:
- reg_bank_access():tot(0),rd(0),wr(0){
- for (unsigned i = 0; i < 4; i++) rd_regs[i] = -1;
- }
- unsigned tot;
- unsigned rd;
- unsigned wr;
- int rd_regs[4];
-};
-
-int register_bank(int regnum, int tid)
-{
- int bank = regnum;
- if (gpgpu_reg_bank_use_warp_id)
- bank += tid >> 5/*log2(warp_size)*/;
- return bank % gpgpu_num_reg_banks;
-}
-
-reg_bank_access g_reg_bank_access[MAX_REG_BANKS];
-
-// just to use as "shorthand" for clearing accesses each cycle
-static const struct reg_bank_access empty_reg_bank_access;
-
-unsigned int gpu_reg_bank_conflict_stalls = 0;
-void shader_opnd_collect_read(shader_core_ctx_t* shader)
+void shader_core_ctx::decode()
{
- const int prevstage = ID_OC;
- shader->m_opndcoll_new.step(shader->pipeline_reg[prevstage]);
-}
-
-void shader_opnd_collect_write(shader_core_ctx_t* shader)
-{
- shader->m_opndcoll_new.writeback(shader->pipeline_reg[WB_RT]);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void shader_decode( shader_core_ctx_t *shader,
- unsigned int shader_number,
- unsigned int grid_num ) {
-
- address_type addr;
- dram_callback_t callback;
op_type op = NO_OP;
- int tid;
- int i1, i2, i3, i4, o1, o2, o3, o4; //4 outputs needed for texture fetches in cuda-sim
- int i;
- int touched_priority=0;
- int warp_tid=0;
- unsigned data_size;
- memory_space_t space;
- unsigned cycles;
- int vectorin, vectorout;
- int arch_reg[MAX_REG_OPERANDS] = { -1 };
- int pred;
- int ar1, ar2; // address registers for memory operands
+ 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 = (gpgpu_operand_collector) ? ID_OC : \
- (shader->using_rrstage ? ID_RR : ID_EX);
- unsigned warp_id = -1;
- unsigned cta_id = -1;
+ const int nextstage = (m_config->gpgpu_operand_collector) ? ID_OC : \
+ (m_config->m_using_dwf_rrstage ? ID_RR : ID_EX);
- // stalling for register bank conflict
- if ( gpgpu_reg_bank_conflict_model ) {
- for (i=0; i<pipe_simd_width;i++) {
- if ( shader->pipeline_reg[IF_ID][i].reg_bank_conflict_stall_checked ) {
- if ( shader->pipeline_reg[IF_ID][i].reg_bank_access_pending > 0 ) {
- assert( shader->pipeline_reg[IF_ID][i].reg_bank_access_pending <= 8 );
- shader->pipeline_reg[IF_ID][i].reg_bank_access_pending--;
- gpu_reg_bank_conflict_stalls++;
- return;
- }
- }
- }
- }
-
- for (i=0; i<pipe_simd_width;i++) {
- if (shader->pipeline_reg[nextstage][i].hw_thread_id != -1 ) {
- return; /* stalled */
- }
- }
+ if( !pipeline_regster_empty(m_pipeline_reg[nextstage]) )
+ return;
- check_stage_pcs(shader,IF_ID);
+ check_stage_pcs(IF_ID);
// decode the instruction
int first_valid_thread = -1;
- for (i=0; i<pipe_simd_width;i++) {
-
- if (shader->pipeline_reg[IF_ID][i].hw_thread_id == -1 )
- continue; /* bubble */
-
- /* get the next instruction to execute from fetch stage */
- tid = shader->pipeline_reg[IF_ID][i].hw_thread_id;
+ 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;
- warp_id = tid/warp_size;
- assert( !shader->warp_waiting_at_barrier(warp_id) );
- cta_id = shader->thread[tid].cta_id;
- }
-
- if ( gpgpu_cuda_sim ) {
- ptx_decode_inst( shader->thread[tid].ptx_thd_info, (unsigned*)&op, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg, &pred, &ar1, &ar2);
- shader->pipeline_reg[IF_ID][i].op = op;
- shader->pipeline_reg[IF_ID][i].pc = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info );
- shader->pipeline_reg[IF_ID][i].ptx_thd_info = shader->thread[tid].ptx_thd_info;
-
- } else {
- abort();
- }
- // put the info into the shader instruction structure
- // - useful in tracking instruction dependency (not needed for now)
- shader->pipeline_reg[IF_ID][i].in[0] = i1;
- shader->pipeline_reg[IF_ID][i].in[1] = i2;
- shader->pipeline_reg[IF_ID][i].in[2] = i3;
- shader->pipeline_reg[IF_ID][i].in[3] = i4;
- shader->pipeline_reg[IF_ID][i].out[0] = o1;
- shader->pipeline_reg[IF_ID][i].out[1] = o2;
- shader->pipeline_reg[IF_ID][i].out[2] = o3;
- shader->pipeline_reg[IF_ID][i].out[3] = o4;
-
- }
-
- // checking for register bank conflict and stall accordingly
- if ( gpgpu_reg_bank_conflict_model &&
- first_valid_thread != -1 &&
- !shader->pipeline_reg[first_valid_thread][IF_ID].reg_bank_conflict_stall_checked )
- {
- for (i = 4; i < 8; i++) {
- if( arch_reg[i] != -1 ) {
- assert( arch_reg[i] >=0 );
- assert( gpgpu_num_reg_banks <= MAX_REG_BANKS );
- int skip = 0;
- int bank = arch_reg[i] % gpgpu_num_reg_banks;
- int opndreg = shader->pipeline_reg[first_valid_thread][IF_ID].in[i-4];
- assert(opndreg >= 0);
- int j;
- for (j = 0; j < 4; j++) {
- if (g_reg_bank_access[bank].rd_regs[j] == -1)
- break;
- else if (g_reg_bank_access[bank].rd_regs[j] == opndreg) {
- // two operands reading from same register in same bank, can be merged into a single read
- skip = 1;
- break;
- }
- }
- if (!skip) {
- g_reg_bank_access[bank].tot++;
- g_reg_bank_access[bank].rd++;
- g_reg_bank_access[bank].rd_regs[j] = opndreg;
- }
- }
- }
-
- unsigned max_access=0;
- inst_t* conflict_inst = &shader->pipeline_reg[first_valid_thread][IF_ID];
- for(unsigned r = 0; r < gpgpu_num_reg_banks; r++ ) {
- if( g_reg_bank_access[r].tot > max_access )
- max_access = g_reg_bank_access[r].tot;
- g_reg_bank_access[r] = empty_reg_bank_access;
- }
- if( max_access >= 1 ) {
- assert( max_access <= MAX_REG_OPERANDS );
- conflict_inst->reg_bank_access_pending = max_access - 1;
- if( max_access > 1 ) {
- conflict_inst->reg_bank_conflict_stall_checked = 1;
- return; // stall pipeline
- }
- }
- shader->pipeline_reg[first_valid_thread][IF_ID].reg_bank_conflict_stall_checked = 1;
+ 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 (i=0; i<pipe_simd_width;i++) {
- if (shader->pipeline_reg[IF_ID][i].hw_thread_id == -1 )
- continue; /* bubble */
+ 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 = shader->pipeline_reg[IF_ID][i].hw_thread_id;
+ last_hw_thread_id = m_pipeline_reg[IF_ID][i].hw_thread_id;
/* get the next instruction to execute from fetch stage */
- tid = shader->pipeline_reg[IF_ID][i].hw_thread_id;
- if ( gpgpu_cuda_sim ) {
- int arch_reg[MAX_REG_OPERANDS];
-
- // Decode instruction
- ptx_decode_inst( shader->thread[tid].ptx_thd_info, (unsigned*)&op, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg, &pred, &ar1, &ar2 );
-
- // Functionally execute instruction
- ptx_exec_inst( shader->thread[tid].ptx_thd_info, &addr, &space, &data_size, &cycles, &callback, shader->pipeline_reg[IF_ID][i].warp_active_mask );
-
- shader->pipeline_reg[IF_ID][i].callback = callback;
- shader->pipeline_reg[IF_ID][i].space = space;
- if (is_local(space) && (is_load(op) || is_store(op))) {
- addr = translate_local_memaddr(addr, shader, tid);
- }
- shader->pipeline_reg[IF_ID][i].is_vectorin = vectorin;
- shader->pipeline_reg[IF_ID][i].is_vectorout = vectorout;
- shader->pipeline_reg[IF_ID][i].pred = pred;
- shader->pipeline_reg[IF_ID][i].ar1 = ar1;
- shader->pipeline_reg[IF_ID][i].ar2 = ar2;
- shader->pipeline_reg[IF_ID][i].data_size = data_size;
- shader->pipeline_reg[IF_ID][i].cycles = cycles;
-
- // Mark destination registers as write-pending in scoreboard
- // Only do this for the first thread in warp
- if(first_thread_in_warp) {
- shader->scrb->reserveRegisters(warp_id, &(shader->pipeline_reg[IF_ID][i]));
- //shader->scrb->printContents();
- }
+ int tid = m_pipeline_reg[IF_ID][i].hw_thread_id;
- warp_current_pc = shader->pipeline_reg[IF_ID][i].pc;
- memcpy( shader->pipeline_reg[IF_ID][i].arch_reg, arch_reg, sizeof(arch_reg) );
- regs_regs_PC = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info );
- }
+ // 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());
- shader->pipeline_reg[IF_ID][i].memreqaddr = addr;
- if ( op == LOAD_OP ) {
- shader->pipeline_reg[IF_ID][i].inst_type = LOAD_OP;
- } else if ( op == STORE_OP ) {
- shader->pipeline_reg[IF_ID][i].inst_type = STORE_OP;
- }
+ // 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 ( gpgpu_cuda_sim && ptx_thread_at_barrier( shader->thread[tid].ptx_thd_info ) ) {
- if (shader->model == DWF) {
- shader->thread[tid].m_waiting_at_barrier=1;
- shader->thread[tid].m_reached_barrier=1; // not reset at barrier release, but at the issue after that
- shader->warp[wid_from_hw_tid(tid,warp_size)].n_waiting_at_barrier++;
- shader->waiting_at_barrier++;
- int cta_uid = ptx_thread_get_cta_uid( shader->thread[tid].ptx_thd_info );
- dwf_hit_barrier( shader->sid, cta_uid );
+ 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( shader->thread[tid].ptx_thd_info ); //test if all threads arrived at the barrier
+ 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( shader->thread[tid].ptx_thd_info );
- for ( unsigned t=0; t < gpu_n_thread_per_shader; ++t ) {
- if ( !ptx_thread_at_barrier( shader->thread[t].ptx_thd_info ) )
+ 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( shader->thread[t].ptx_thd_info );
+ 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
- shader->warp[wid_from_hw_tid(t,warp_size)].n_waiting_at_barrier=0;
- shader->thread[t].m_waiting_at_barrier=0;
- ptx_thread_reset_barrier( shader->thread[t].ptx_thd_info );
- shader->waiting_at_barrier--;
+ 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 (shader->model == DWF) {
- dwf_release_barrier( shader->sid, cta_uid );
+ if (m_config->model == DWF) {
+ dwf_release_barrier( m_sid, cta_uid );
}
- ptx_thread_release_barrier( shader->thread[tid].ptx_thd_info );
+ ptx_thread_release_barrier( m_thread[tid].m_functional_model_thread_state );
}
}
} else {
- assert( !shader->thread[tid].m_waiting_at_barrier );
+ assert( !m_thread[tid].m_waiting_at_barrier );
}
- // put the info into the shader instruction structure
- // - useful in tracking instruction dependency (not needed for now)
- shader->pipeline_reg[IF_ID][i].in[0] = i1;
- shader->pipeline_reg[IF_ID][i].in[1] = i2;
- shader->pipeline_reg[IF_ID][i].in[2] = i3;
- shader->pipeline_reg[IF_ID][i].in[3] = i4;
- shader->pipeline_reg[IF_ID][i].out[0] = o1;
- shader->pipeline_reg[IF_ID][i].out[1] = o2;
- shader->pipeline_reg[IF_ID][i].out[2] = o3;
- shader->pipeline_reg[IF_ID][i].out[3] = o4;
-
- // go to the next instruction
- // - done implicitly in ptx_exec_inst()
-
// branch divergence detection
if (warp_next_pc != regs_regs_PC) {
if (warp_next_pc == 0x600DBEEF) {
@@ -2003,21 +1528,16 @@ void shader_decode( shader_core_ctx_t *shader,
warp_diverging = 1;
}
}
-
- // direct the instruction to the appropriate next stage (config dependent)
- shader->pipeline_reg[nextstage][i] = shader->pipeline_reg[IF_ID][i];
- shader->pipeline_reg[nextstage][i].id_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
- shader->pipeline_reg[IF_ID][i] = nop_inst;
}
- if( op == BARRIER_OP ) {
- shader->set_at_barrier(cta_id,warp_id);
- }
+ move_warp(m_pipeline_reg[nextstage],m_pipeline_reg[IF_ID]);
- if ( shader->model == NO_RECONVERGE && touched_priority ) {
- update_max_branch_priority(shader,warp_tid,grid_num);
- }
- shader->n_diverge += warp_diverging;
+ 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);
@@ -2036,451 +1556,381 @@ int regfile_hash(signed thread_number, unsigned simd_size, unsigned n_banks) {
}
}
-int gpgpu_n_reg_banks = 8;
-void shader_preexecute( shader_core_ctx_t *shader,
- unsigned int shader_number ) {
- int i;
- static int *thread_warp = NULL;
- int n_access_per_cycle = pipe_simd_width / gpgpu_n_reg_banks;
-
- if (!thread_warp) {
- thread_warp = (int*) malloc(sizeof(int) * pipe_simd_width);
- }
+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).
- for (i=0; i<pipe_simd_width; i++) {
- if (shader->pipeline_reg[RR_EX][i].hw_thread_id != -1 ) {
- //stalled, but can still service a register read
- if (shader->RR_k) {
- shader->RR_k--;
+ 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;
}
- return; // stalled
- }
- }
-
- // if there is still register read to service, stall
- if (shader->RR_k > 1) {
- shader->RR_k--;
- return;
- }
-
- // if RR_k == 1, it was stalled previously and the register read is now done
- if (!shader->RR_k && gpgpu_reg_bankconflict) {
- int max_reg_bank_acc = 0;
- for (i=0; i<pipe_simd_width; i++) {
- thread_warp[i] = 0;
- }
- for (i=0; i<pipe_simd_width; i++) {
- if (shader->pipeline_reg[ID_RR][i].hw_thread_id != -1 )
- thread_warp[regfile_hash(shader->pipeline_reg[ID_RR][i].hw_thread_id,
- warp_size, gpgpu_n_reg_banks)]++;
- }
- for (i=0; i<pipe_simd_width; i++) {
- if (thread_warp[i] > max_reg_bank_acc ) {
- max_reg_bank_acc = thread_warp[i];
+
+ 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;
}
}
- // calculate the number of cycles needed for each register bank to fulfill all accesses
- shader->RR_k = (max_reg_bank_acc / n_access_per_cycle) + ((max_reg_bank_acc % n_access_per_cycle)? 1 : 0);
- }
-
- // if there are more than one access cycle needed at a bank, stall
- if (shader->RR_k > 1) {
- n_regconflict_stall++;
- shader->RR_k--;
- return;
- }
-
- check_stage_pcs(shader,ID_RR);
-
- shader->RR_k = 0; //setting RR_k to 0 to indicate RF conflict check next cycle
- for (i=0; i<pipe_simd_width;i++) {
- if (shader->pipeline_reg[ID_RR][i].hw_thread_id == -1 )
- continue; //bubble
- shader->pipeline_reg[ID_EX][i] = shader->pipeline_reg[ID_RR][i];
- shader->pipeline_reg[ID_RR][i] = nop_inst;
+
+ 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_execute_pipe( shader_core_ctx_t *shader, unsigned int shader_number, unsigned pipeline, unsigned next_stage )
+void shader_core_ctx::execute_pipe( unsigned pipeline, unsigned next_stage )
{
- int i;
- for (i=0; i<pipe_simd_width; i++) {
- if (gpgpu_pre_mem_stages) {
- if (shader->pre_mem_pipeline[0][i].hw_thread_id != -1 ) {
- return; // stalled
- }
- } else {
- if (shader->pipeline_reg[next_stage][i].hw_thread_id != -1 )
- return; // stalled
- }
+ 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(shader,ID_EX);
+
+ check_stage_pcs(ID_EX);
// Check that all threads have the same delay cycles
unsigned cycles = -1;
- for (i=0; i<pipe_simd_width; i++) {
- if (shader->pipeline_reg[pipeline][i].hw_thread_id == -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 = shader->pipeline_reg[pipeline][i].cycles;
+ cycles = m_pipeline_reg[pipeline][i].cycles;
else {
- if( cycles != shader->pipeline_reg[pipeline][i].cycles ) {
- printf("Shader %d: threads do not have the same delay cycles.\n", shader->sid);
+ if( cycles != m_pipeline_reg[pipeline][i].cycles ) {
+ printf("Shader %d: threads do not have the same delay cycles.\n", m_sid);
assert(0);
}
}
}
- for (i=0; i<pipe_simd_width; i++) {
- if (shader->pipeline_reg[pipeline][i].hw_thread_id == -1 )
- continue; // bubble
-
- // Stall based on delay cycles
- shader->pipeline_reg[pipeline][i].cycles--;
- if( shader->pipeline_reg[pipeline][i].cycles > 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 (gpgpu_pre_mem_stages) {
- shader->pre_mem_pipeline[0][i] = shader->pipeline_reg[pipeline][i];
- shader->pre_mem_pipeline[0][i].ex_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
- } else {
- shader->pipeline_reg[next_stage][i] = shader->pipeline_reg[pipeline][i];
- shader->pipeline_reg[next_stage][i].ex_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
}
- shader->pipeline_reg[pipeline][i] = nop_inst;
- }
-
- if (!gpgpu_pre_mem_stages) {
+ }
+ 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
- shader->shader_memory_new_instruction_processed = 0;
+ m_shader_memory_new_instruction_processed = false;
}
}
-void shader_execute( shader_core_ctx_t *shader, unsigned int shader_number )
+void shader_core_ctx::execute()
{
- shader_execute_pipe(shader,shader_number, OC_EX_SFU, EX_MM);
- shader_execute_pipe(shader,shader_number, ID_EX, EX_MM);
+ execute_pipe(OC_EX_SFU, EX_MM);
+ execute_pipe(ID_EX, EX_MM);
}
-void shader_pre_memory( shader_core_ctx_t *shader,
- unsigned int shader_number ) {
- int i,j;
-
-
- for (j = gpgpu_pre_mem_stages; j > 0; j--) {
- for (i=0; i<pipe_simd_width; i++) {
- if (shader->pre_mem_pipeline[j][i].hw_thread_id != -1 ) {
- return;
- }
- }
- check_pm_stage_pcs(shader,j-1);
- for (i=0; i<pipe_simd_width; i++) {
- shader->pre_mem_pipeline[j][i] = shader->pre_mem_pipeline[j - 1][i];
- shader->pre_mem_pipeline[j - 1][i] = nop_inst;
- }
+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;
}
- check_pm_stage_pcs(shader,gpgpu_pre_mem_stages);
- for (i=0;i<pipe_simd_width ;i++ )
- shader->pipeline_reg[EX_MM][i] = shader->pre_mem_pipeline[gpgpu_pre_mem_stages][i];
-
- // inform memory stage that a new instruction has arrived
- shader->shader_memory_new_instruction_processed = 0;
-
- if (gpgpu_pre_mem_stages) {
- for (i=0; i<pipe_simd_width; i++)
- shader->pre_mem_pipeline[0][i] = nop_inst;
+ 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]);
}
}
-int gpgpu_coalesce_arch;
-
-enum memory_path {
- NO_MEM_PATH = 0,
- SHARED_MEM_PATH,
- GLOBAL_MEM_PATH,
- TEXTURE_MEM_PATH,
- CONSTANT_MEM_PATH,
- NUM_MEM_PATHS //not a mem path
-};
-
-static unsigned next_access_uid = 0;
-
-class mem_access_t{
-public:
- mem_access_t(): uid(next_access_uid++),addr(0),req_size(0),order(0),_quarter_count_all(0),warp_indices(),space(undefined_space),path(NO_MEM_PATH),isatomic(false),cache_hit(false),cache_checked(false),recheck_cache(false),iswrite(false),need_wb(false),wb_addr(0),reserved_mshr(NULL){};
- bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse
- unsigned uid;
- address_type addr; //address of the segment to load.
- unsigned req_size; //bytes
- unsigned order; // order of accesses, based on banks.
- union{
- unsigned _quarter_count_all;
- char quarter_count[4]; //access counts to each quarter of segment, for compaction;
- };
- std::vector<unsigned> warp_indices; //warp indicies for this request.
- memory_space_t space;
- memory_path path;
- bool isatomic;
- bool cache_hit;
- bool cache_checked;
- bool recheck_cache;
- bool iswrite;
- bool need_wb;
- address_type wb_addr; //address to wb too if necessary.
- mshr_entry_t* reserved_mshr;
-};
-
-mshr_entry_t* mshr_shader_unit::add_mshr(mem_access_t &access, inst_t* warp)
+mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, inst_t* warp)
{
- static unsigned next_request_uid = 1;
- mshr_entry_t* mshr = alloc_free_mshr(is_tex(access.space));
- //note no constructor was called, all entries must be reinitialized!
- mshr->request_uid = next_request_uid++;
- mshr->status = INITIALIZED;
- mshr->addr = access.addr;
- mshr->mf = NULL;
- mshr->merged_on_other_reqest = false;
- mshr->merged_requests =NULL;
- mshr->iswrite = access.iswrite;
- 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->insts.push_back(warp[access.warp_indices[i]]);
- }
- mshr->islocal = is_local(access.space);
- mshr->isconst = is_const(access.space);
- mshr->istexture = is_tex(access.space);
- if (gpgpu_interwarp_mshr_merge) {
- mshr_entry_t* mergehit = m_mshr_lookup.shader_get_mergeable_mshr(mshr);
- if (mergehit) {
- //merge this request;
- mergehit->merged_requests = mshr;
- mshr->merged_on_other_reqest = true;
- if (mergehit->fetched()) mshr_return_from_mem(mshr);
- }
- m_mshr_lookup.mshr_fast_lookup_insert(mshr);
- }
- return mshr;
+ //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);
+ 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) {
+ mshr_entry* mergehit = m_mshr_lookup.shader_get_mergeable_mshr(mshr);
+ if (mergehit) {
+ mergehit->merge(mshr);
+ if (mergehit->fetched())
+ mshr_return_from_mem(mshr);
+ }
+ m_mshr_lookup.mshr_fast_lookup_insert(mshr);
+ }
+ return mshr;
}
-
-inline address_type line_size_based_tag_func(address_type address, unsigned line_size)
+address_type line_size_based_tag_func(address_type address, unsigned line_size)
{
+ //gives the tag for an address based on a given line size
return ((address) & (~((address_type)line_size - 1)));
}
-inline address_type null_tag_func(address_type address, unsigned line_size){
+address_type null_tag_func(address_type address, unsigned line_size)
+{
return address; //no modification: each address is its own tag. Equivalent to line_size_based_tag_func(address,1), but line_size ignored.
}
// only 1 bank
-inline int null_bank_func(address_type add, unsigned line_size)
+int shader_core_ctx::null_bank_func(address_type add, unsigned line_size)
{
return 1;
}
-inline int shmem_bank_func(address_type add, unsigned line_size)
+int shader_core_ctx::shmem_bank_func(address_type addr, unsigned line_size)
{
- return shmem_bank(add);
+ //returns the integer number of the physical bank addr would go in.
+ return ((int)(addr/((address_type)WORD_SIZE)) % m_config->gpgpu_n_shmem_bank);
}
-inline int dcache_bank_func(address_type add, unsigned line_size)
+int shader_core_ctx::dcache_bank_func(address_type add, unsigned line_size)
{
- if (gpgpu_no_dl1) return 1; //no banks
- else return (add / line_size) & (gpgpu_n_cache_bank - 1);
+ //returns the integer number of the physical bank addr would go in.
+ if (m_config->gpgpu_no_dl1) return 1; //no banks
+ else return (add / line_size) & (m_config->gpgpu_n_cache_bank - 1);
}
-#include <bitset>
-void check_accessq( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq ){
- std::bitset<32> check = 0;
- for (unsigned i = 0; i < accessq.size(); i++) {
- if (shader) {
- std::cout << shader->sid << ":" << i << " space " << accessq[i].space.get_type() << " " << gpu_sim_cycle << std::endl;
- assert(accessq[i].space == shader->pipeline_reg[EX_MM][accessq[i].warp_indices[0]].space);
- }
- for (unsigned j = 0; j < accessq[i].warp_indices.size(); j++) {
- if (check[accessq[i].warp_indices[j]]) {
- std::cout << "OOOPS" << std::endl; //good line for breakpoint
- }else{check[accessq[i].warp_indices[j]] = true;}
- }
- }
-}
+typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size);
+typedef address_type (*tag_func_t)(address_type add, unsigned line_size);
-// This speciallized function calculates the list of independant memory accesses, sorted by access order
-// Acesses to same tag line are coalesced.
-// will neither coalesce nor overlap bank accesses accross warp parts.
-template < int (*bank_func)(address_type add, unsigned line_size), address_type (*tag_func)(address_type add, unsigned line_size) >
-inline void get_memory_access_list(inst_t* insns, unsigned char* paths, memory_path path, unsigned warp_parts, unsigned line_size, bool limit_broadcast,std::vector<mem_access_t> &accessq)
+void shader_core_ctx::get_memory_access_list(
+ shader_core_ctx::bank_func_t bank_func,
+ tag_func_t tag_func,
+ memory_pipe_t mem_pipe,
+ unsigned warp_parts,
+ unsigned line_size,
+ bool limit_broadcast,
+ std::vector<mem_access_t> &accessq )
{
- // calculates the memory accesses for a generic cache with banks and tags.
- // can be used for coalesescing
+ const 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".
- //tracks bank accesses for sorting into generations;
- static std::map<unsigned,unsigned> bank_accs;
- bank_accs.clear();
- //keep track of broadcasts with unique orders if limit_broadcast
- //the normally calculated orders will never be greater than pipe_simd_width;
- unsigned broadcast_order = pipe_simd_width;
+ // This is called once per warp when it enters the memory stage.
+ // It takes the warp and produces a queue of accesses that can be peformed.
+ // These are then performed over multiple cycles (stalling the pipeline) if the accessses cannot be
+ // performed all at once.
+ // It is a convenience for simulation; in hardware the warp would be processed each cycle
+ // until it was done. Each cycle would do the first accesses available to it and mark off the
+ // those threads served by those accesses.
+
+ // Because it calculates all the accesses at once, what follows is largely not as the hw would do it.
+ // Accesses are assigned an order number based on when that access may be issued.
+ // Accesses with the same order number may occur at the same time: they are to different banks.
+ // Later when the queue is processed it will evaluate accesses of
+ // as many orders as ports on that cache/shmem.
+ // These accesses are placed into a queue and sorted so that accesses of the same order are next to each other.
+
+
+ // tracks bank accesses for sorting into generations;
+ // each entry is (bank #, number of accesses)
+ // the idea is that you can only access a bank a number of times each cycle equal to
+ // its number of ports in one cycle.
+ std::map<unsigned,unsigned> bank_accs;
+
+ //keep track of broadcasts with unique orders if limit_broadcast
+ //the normally calculated orders will never be greater than warp_size
+ unsigned broadcast_order = m_config->warp_size;
unsigned qbegin = accessq.size();
unsigned qpartbegin = qbegin;
- unsigned mem_pipe_size = pipe_simd_width / warp_parts;
- for (unsigned part = 0; part < (unsigned)pipe_simd_width; part += mem_pipe_size) {
+ 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 (paths[i] != path) continue; //skip instructions from other memory paths
- address_type segment = (*tag_func)(insns[i].memreqaddr, line_size);
- unsigned quarter=0;
- if ( line_size>=4 ) {
- quarter = (insns[i].memreqaddr / (line_size/4)) & 3;
- }
- //check if we are already loading this segment.
+ if ( insns[i].hw_thread_id == -1 )
+ 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);
+ unsigned quarter = 0;
+ if( line_size>=4 )
+ quarter = (insns[i].memreqaddr / (line_size/4)) & 3;
bool isatomic = (insns[i].callback.function != NULL);
- unsigned match = 0;
+ bool match = false;
if (not isatomic) { //atomics must have own request
for (unsigned j = qpartbegin; j < accessq.size(); j++) {
- if (segment == accessq[j].addr and not accessq[j].isatomic) {
- //match
+ 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) accessq[j].order = ++broadcast_order; //do proadcast in its own cycle.
- match = 1;
+ 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;
}
}
}
- if (!match) {
- //needs its own request
- accessq.push_back(mem_access_t());
- accessq.back().addr = segment;
- accessq.back().space = insns[i].space;
- accessq.back().path = path;
- accessq.back().isatomic = isatomic;
- accessq.back().iswrite = is_store(insns[i].op);
- accessq.back().req_size = line_size;
- accessq.back().quarter_count[quarter]++;
- accessq.back().warp_indices.push_back(i);
-
- //Determine Bank Conflicts.
- unsigned bank = (*bank_func)(insns[i].memreqaddr, line_size);
- //ensure no concurrent bank access accross warp parts.
+ if (!match) { // does not match an previous request by another thread, so need a new request
+ assert( insns[i].space != undefined_space );
+ accessq.push_back( mem_access_t( lane_segment_address,
+ insns[i].space,
+ mem_pipe,
+ isatomic,
+ is_store(insns[i]),
+ line_size, quarter, i) );
+ // Determine Bank Conflicts:
+ unsigned bank = (this->*bank_func)(insns[i].memreqaddr, 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) bank_accs[bank]=part;
+ if (bank_accs[bank] < part)
+ bank_accs[bank]=part;
accessq.back().order = bank_accs[bank];
bank_accs[bank]++;
}
}
qpartbegin = accessq.size(); //don't coalesce accross warp parts
}
- //sort requests into order accorting to order (orders will not necessarily be consequtive if multiple parts)
- std::stable_sort(accessq.begin()+qbegin,accessq.end()); //this is a reverse sort, least order last, but doesn't really matter where consumed.
-}
+ //sort requests into order according to order (orders will not necessarily be consequtive if multiple parts)
+ std::stable_sort(accessq.begin()+qbegin,accessq.end());
+}
-void shader_memory_shared_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq)
+void shader_core_ctx::memory_shared_process_warp()
{
- get_memory_access_list<&shmem_bank_func, &null_tag_func>(shader->pipeline_reg[EX_MM], paths, SHARED_MEM_PATH,
- gpgpu_shmem_pipe_speedup,
+ // initial processing of shared memory warps
+ get_memory_access_list(&shader_core_ctx::shmem_bank_func,
+ null_tag_func,
+ SHARED_MEM_PATH,
+ m_config->gpgpu_shmem_pipe_speedup,
1, //shared memory doesn't care about line_size, needs to be at least 1;
- true, //limit broadcasts to single cycle.
- accessq);
- //thats it :)
+ true, // limit broadcasts to single cycle.
+ m_memory_queue.shared);
}
-void shader_memory_const_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq)
+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<&null_bank_func, &line_size_based_tag_func>(shader->pipeline_reg[EX_MM], paths, CONSTANT_MEM_PATH,
- 1, //warp parts
- shader->L1constcache->line_sz,
- false, //no broadcast limit.
- accessq);
- //do cache checks here for each request, could be done later for more accurate timing of cache accesses, but probably uneccesary;
+ get_memory_access_list(
+ &shader_core_ctx::null_bank_func,
+ line_size_based_tag_func,
+ CONSTANT_MEM_PATH,
+ 1, //warp parts
+ m_L1C->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 (is_param(accessq[i].space)) {
+ if ( accessq[i].space == param_space_kernel ) {
accessq[i].cache_hit = true;
} else {
- cache_request_status status = shd_cache_access_wb(shader->L1constcache,
+ cache_request_status status = shd_cache_access_new(m_L1C,
accessq[i].addr,
WORD_SIZE, //this field is ingored.
0, //should always be a read
- shader->gpu_cycle,
+ gpu_sim_cycle+gpu_tot_sim_cycle,
NULL/*should never writeback*/);
accessq[i].cache_hit = (status == HIT);
- if (gpgpu_perfect_mem) accessq[i].cache_hit = true;
- if (accessq[i].cache_hit) L1_const_miss++;
+ 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_memory_texture_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq)
+void shader_core_ctx::memory_texture_process_warp()
{
+ // initial processing of shared texture warps
+ std::vector<mem_access_t> &accessq = m_memory_queue.texture;
unsigned qbegin = accessq.size();
- get_memory_access_list<&null_bank_func, &line_size_based_tag_func>(shader->pipeline_reg[EX_MM], paths, TEXTURE_MEM_PATH,
+ get_memory_access_list(&shader_core_ctx::null_bank_func,
+ &line_size_based_tag_func,
+ TEXTURE_MEM_PATH,
1, //warp parts
- shader->L1texcache->line_sz,
+ m_L1T->line_sz,
false, //no broadcast limit.
accessq);
- //do cache checks here for each request, 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 = shd_cache_access_wb(shader->L1texcache,
+ cache_request_status status = shd_cache_access_new(m_L1T,
accessq[i].addr,
WORD_SIZE, //this field is ignored.
0, //should always be a read
- shader->gpu_cycle,
+ gpu_sim_cycle+gpu_tot_sim_cycle,
NULL /*should never writeback*/);
accessq[i].cache_hit = (status == HIT);
- if (gpgpu_perfect_mem) accessq[i].cache_hit = true;
- if (accessq[i].cache_hit) L1_texture_miss++;
+ if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true;
+ if (accessq[i].cache_hit) m_stats->L1_texture_miss++;
accessq[i].cache_checked = true;
}
}
-void shader_memory_global_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq)
+void shader_core_ctx::memory_global_process_warp()
{
+ std::vector<mem_access_t> &accessq = m_memory_queue.local_global;
unsigned qbegin = accessq.size();
unsigned warp_parts = 1;
- unsigned line_size = shader->L1cache->line_sz;
- if (gpgpu_coalesce_arch == 13) {
+ unsigned line_size = m_L1D->line_sz;
+ if (m_config->gpgpu_coalesce_arch == 13) {
warp_parts = 2;
- if(gpgpu_no_dl1) {
- int valindex = -1;
- for (int i = 0; i < pipe_simd_width; i++) {
- if (paths[i] == GLOBAL_MEM_PATH) {
- valindex = i;
- break;
- }
- }
- assert(valindex != -1);
+ if(m_config->gpgpu_no_dl1) {
+ unsigned data_size = first_valid_thread( m_pipeline_reg[EX_MM] )->data_size;
// line size is dependant on instruction;
- //assume first valid thread instruction is the same as the rest.
- switch (shader->pipeline_reg[EX_MM][valindex].data_size) {
- case 1:
- line_size = 32;
- break;
- case 2:
- line_size = 64;
- break;
- case 4:
- case 8:
- case 16:
- line_size = 128;
- break;
- default:
- assert(0);
+ switch (data_size) {
+ case 1: line_size = 32; break;
+ case 2: line_size = 64; break;
+ case 4: case 8: case 16: line_size = 128; break;
+ default: assert(0);
}
}
}
- get_memory_access_list<&dcache_bank_func, &line_size_based_tag_func>(shader->pipeline_reg[EX_MM], paths, GLOBAL_MEM_PATH,
- warp_parts, //warp parts
- line_size,
- false, //no broadcast limit.
- accessq);
+ get_memory_access_list( &shader_core_ctx::dcache_bank_func,
+ &line_size_based_tag_func,
+ GLOBAL_MEM_PATH,
+ warp_parts,
+ line_size,
+ false,
+ accessq);
+ // Now that we have the accesses, if we don't have a cache we can adjust request sizes to
+ // include only the data referenced by the threads
for (unsigned i = qbegin; i < accessq.size(); i++) {
- if (gpgpu_coalesce_arch == 13 and gpgpu_no_dl1) {
+ if (m_config->gpgpu_coalesce_arch == 13 and m_config->gpgpu_no_dl1) {
//if there is no l1 cache it makes sense to do coalescing here.
//reduce memory request sizes.
char* quarter_counts = accessq[i].quarter_count;
@@ -2506,242 +1956,195 @@ void shader_memory_global_process_inst(shader_core_ctx_t * shader, unsigned char
-mem_stage_stall_type send_mem_request(shader_core_ctx_t *shader, mem_access_t &access){
- inst_t* warp = shader->pipeline_reg[EX_MM];
+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];
+ // 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.
if (access.need_wb) {
- //fill out and send a writeback
- unsigned req_size = shader->L1cache->line_sz + WRITE_PACKET_SIZE;
- if (!(shader->fq_has_buffer(access.wb_addr, req_size, true, shader->sid))) {
- gpu_stall_sh2icnt++;
+ unsigned req_size = m_L1D->line_sz + WRITE_PACKET_SIZE;
+ if ( ! m_gpu->fq_has_buffer(access.wb_addr, req_size, true, m_sid) ) {
+ m_stats->gpu_stall_sh2icnt++;
return WB_ICNT_RC_FAIL;
}
-
- shader->fq_push( access.wb_addr,
- req_size,
- true, NO_PARTIAL_WRITE, shader->sid, -1, NULL,
- 0,
- is_local(access.space)?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request
+ fq_push( access.wb_addr, req_size, true, NO_PARTIAL_WRITE, -1, NULL, 0,
+ is_local(access.space)?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request
-1);
- L1_writeback++;
+ m_stats->L1_writeback++;
access.need_wb = false;
}
- bool requires_mshr = (shader->model != MIMD) and (not access.iswrite);
-
- //this decoding here might belong elsewhere
unsigned code;
- mem_access_type access_type;
+ mem_access_type access_type;
switch(access.space.get_type()) {
case const_space:
- case param_space_kernel:
- code = CONSTC;
- access_type = CONST_ACC_R;
- break;
- case tex_space:
- code = TEXTC;
- access_type = TEXTURE_ACC_R;
- break;
- case global_space:
- code = DCACHE;
- access_type = (access.iswrite)? GLOBAL_ACC_W: GLOBAL_ACC_R;
- break;
+ case param_space_kernel: code = CONSTC; access_type = CONST_ACC_R; break;
+ case tex_space: code = TEXTC; access_type = TEXTURE_ACC_R; break;
+ case global_space: code = DCACHE; access_type = (access.iswrite)? GLOBAL_ACC_W: GLOBAL_ACC_R; break;
case local_space:
- case param_space_local:
- code = DCACHE;
- access_type = (access.iswrite)? LOCAL_ACC_W: LOCAL_ACC_R;
- break;
- default:
- assert(0); // NOT A MEM SPACE;
- break;
+ case param_space_local: code = DCACHE; access_type = (access.iswrite)? LOCAL_ACC_W: LOCAL_ACC_R; break;
+ default: assert(0); break;
}
-
//reserve mshr
+ bool requires_mshr = (m_config->model != MIMD) and (not access.iswrite);
if (requires_mshr and not access.reserved_mshr) {
-
- // can allocate mshr?
- if (not shader->mshr_unit->has_mshr(1)) {
- //no mshr available;
+ if (not m_mshr_unit->has_mshr(1))
return MSHR_RC_FAIL;
- }
-
- access.reserved_mshr = shader->mshr_unit->add_mshr(access, warp);
+ access.reserved_mshr = m_mshr_unit->add_mshr(access, warp);
access.recheck_cache = false; //we have an mshr now, so have checked cache in same cycle as checking mshrs, so have merged if necessary.
}
-
//require inct if access is this far without reserved mshr, or has and mshr but not merged with another request
- bool requires_icnt = (not access.reserved_mshr) or (not access.reserved_mshr->merged_on_other_reqest);
-
+ bool requires_icnt = (not access.reserved_mshr) or (not access.reserved_mshr->ismerged() );
if (requires_icnt) {
-
//calculate request size for icnt check (and later send);
unsigned request_size = access.req_size;
if (access.iswrite) {
- if (requires_mshr) {
- //needs information for a load back into cache.
- request_size += READ_PACKET_SIZE + WRITE_MASK_SIZE;
- } else {
- //plain write
- request_size += WRITE_PACKET_SIZE + WRITE_MASK_SIZE;
- }
+ if (requires_mshr)
+ request_size += READ_PACKET_SIZE + WRITE_MASK_SIZE; // needs information for a load back into cache.
+ else
+ request_size += WRITE_PACKET_SIZE + WRITE_MASK_SIZE; //plain write
}
-
-
- // can allocate icnt?
- //unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid);
- if (!(shader->fq_has_buffer(access.addr, request_size, access.iswrite, shader->sid))) {
- gpu_stall_sh2icnt++;
- //std::cout<< "failed to push " << request_size << " bytes" << std::endl;
+ if ( !m_gpu->fq_has_buffer(access.addr, request_size, access.iswrite, m_sid) ) {
+ // can't allocate icnt
+ m_stats->gpu_stall_sh2icnt++;
return ICNT_RC_FAIL;
}
-
//send over interconnect
-
- unsigned cache_hits_waiting = 0; //fixme do we really want to be passing this in?
-
+ unsigned cache_hits_waiting = 0;
partial_write_mask_t write_mask = NO_PARTIAL_WRITE;
+ unsigned warp_id = req_head->hw_thread_id/m_config->warp_size;
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);
}
- if (write_mask.count() != access.req_size) {
- gpgpu_n_partial_writes++;
- }
+ if (write_mask.count() != access.req_size)
+ m_stats->gpgpu_n_partial_writes++;
}
-
- //typedef unsigned char (*fq_push_t)(unsigned long long int addr, int bsize, unsigned char readwrite,
- // unsigned long long int partial_write_mask,
- // int sid, int wid, mshr_entry* mshr, int cache_hits_waiting,
- // enum mem_access_type mem_acc, address_type pc);
- shader->fq_push( access.addr,
- request_size,
- access.iswrite, write_mask, shader->sid, req_head->hw_thread_id/warp_size, access.reserved_mshr,
- cache_hits_waiting, access_type, req_head->pc);
-
+ fq_push( access.addr, request_size,
+ access.iswrite, write_mask, warp_id , access.reserved_mshr,
+ cache_hits_waiting, access_type, req_head->pc);
}
-
- //book keeping for mshr since this request is done (sent/accounted for) at this point;
+ // 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];
- shader->pending_mem_access++;
- inflight_memory_insn_add(shader, &warp[o]);
-
-#if 0 //old stats
- if (i > 0) { //maintain old stats (yes/no?)
- shader->thread[warp[o].hw_thread_id].n_l1_mrghit_ac++;
- shd_cache_mergehit(shader->L1texcache, warp[o].memreqaddr); //fixme;
- }
-#endif
+ 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];
- //shader->pipeline_reg[EX_MM][o] = nop_inst;
- shader->pipeline_reg[EX_MM][o].cache_miss = true;
+ m_pipeline_reg[EX_MM][o].cache_miss = true;
}
}
-
}
-
return NO_RC_FAIL;
}
-bool shader_memory_shared_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq,
- mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){
+bool shader_core_ctx::memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+{
+ // Process a single cycle of activity from the shared memory queue.
+
+ std::vector<mem_access_t> &accessq = m_memory_queue.shared;
//consume port number orders from the top of the queue;
- for (unsigned i = 0; i < (unsigned) gpgpu_shmem_port_per_bank; i++) {
- if (accessq.empty()) break;
+ for (int i = 0; i < m_config->gpgpu_shmem_port_per_bank; i++) {
+ if (accessq.empty())
+ break;
unsigned current_order = accessq.back().order;
//consume all requests of the same order (concurrent bank requests)
- while ((not accessq.empty()) and accessq.back().order == current_order) accessq.pop_back();
+ while ((not accessq.empty()) and accessq.back().order == current_order)
+ accessq.pop_back();
}
if (not accessq.empty()) {
rc_fail = BK_CONF;
fail_type = S_MEM;
- gpgpu_n_shmem_bkconflict++;
+ m_stats->gpgpu_n_shmem_bkconflict++;
}
return accessq.empty(); //done if empty.
}
-//generic memory access queue processing, accessq must be sorted by order
-//--that is, requests of similar order are expected to be contiguous in the queueu.
-//if you want to use this for shared memory, make sure they are marked as cashe hits (not default)
-// cycle_exec may be called multiple times if memory fails. typically used for cache checks
-template < mem_stage_stall_type (*cycle_exec)(shader_core_ctx_t*, mem_access_t&) >
-inline mem_stage_stall_type shader_memory_generic_process_queue( shader_core_ctx_t *shader,
- unsigned ports_per_bank, unsigned memory_send_max,
- std::vector<mem_access_t> &accessq ){
- mem_stage_stall_type rc_fail = NO_RC_FAIL;
- // number of requests to sent to memory this cycle
- unsigned mem_req_count = 0;
- //consume port number orders from the top of the queue;
+mem_stage_stall_type shader_core_ctx::process_memory_access_queue( shader_core_ctx::cache_check_t cache_check,
+ unsigned ports_per_bank,
+ unsigned memory_send_max,
+ std::vector<mem_access_t> &accessq )
+{
+ // Generic algorithm for processing a single cycle of accesses for the memory space types that go to L2 or DRAM.
+
+ // precondition: accessq sorted by mem_access_t::order
+ mem_stage_stall_type hazard_cond = NO_RC_FAIL;
+ unsigned mem_req_count = 0; // number of requests to sent to memory this cycle
for (unsigned i = 0; i < ports_per_bank; i++) {
- if (accessq.empty()) break;
+ if (accessq.empty())
+ break;
unsigned current_order = accessq.back().order;
- //consume all requests of the same order (concurrent bank requests)
- //stop when things that go to memory exceed a per cycle limit.
- while ((not accessq.empty()) and accessq.back().order == current_order and rc_fail == NO_RC_FAIL) {
- rc_fail = (*cycle_exec)(shader, accessq.back());
- if (rc_fail != NO_RC_FAIL) break; //can't complete this request this cycle.
+ // consume all requests of the same "order" but stop if we hit a structural hazard
+ while ((not accessq.empty()) and accessq.back().order == current_order and hazard_cond == NO_RC_FAIL) {
+ hazard_cond = (this->*cache_check)(accessq.back());
+ if (hazard_cond != NO_RC_FAIL)
+ break; // can't complete this request this cycle.
if (not accessq.back().cache_hit){
if (mem_req_count < memory_send_max) {
mem_req_count++;
- rc_fail = send_mem_request(shader, accessq.back()); //try to get mshr, icnt, send;
+ hazard_cond = send_mem_request(accessq.back()); // attemp to get mshr, icnt, send;
}
- else {
- rc_fail = COAL_STALL; //not really a coal stall, its a too many memory request stall;
- }
- if (rc_fail != NO_RC_FAIL) break; //can't complete this request this cycle.
+ else hazard_cond = COAL_STALL; // not really a coal stall, its a too many memory request stall;
+ if ( hazard_cond != NO_RC_FAIL) break; //can't complete this request this cycle.
}
accessq.pop_back();
}
}
- if (not accessq.empty() and rc_fail == NO_RC_FAIL) {
+ if (not accessq.empty() and hazard_cond == NO_RC_FAIL) {
//no resource failed so must be a bank comflict.
- rc_fail = BK_CONF;
+ hazard_cond = BK_CONF;
}
- return rc_fail;
+ return hazard_cond;
}
-mem_stage_stall_type ccache_check(shader_core_ctx_t *shader, mem_access_t& access){ /*done in process queue*/ return NO_RC_FAIL;}
+bool shader_core_ctx::memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+{
+ // Process a single cycle of activity from the the constant memory queue.
-bool shader_memory_constant_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq,
- mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){
+ std::vector<mem_access_t> &accessq = m_memory_queue.constant;
- mem_stage_stall_type fail = shader_memory_generic_process_queue<ccache_check>( shader, gpgpu_const_port_per_bank,
- 1, //memory send max per cycle
- accessq );
+ mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::ccache_check,
+ m_config->gpgpu_const_port_per_bank,
+ 1, //memory send max per cycle
+ accessq );
if (fail != NO_RC_FAIL){
rc_fail = fail; //keep other fails if this didn't fail.
fail_type = C_MEM;
if (rc_fail == BK_CONF or rc_fail == COAL_STALL) {
- gpgpu_n_cmem_portconflict++; //coal stalls aren't really a bank conflict, but this maintains previous behavior.
+ m_stats->gpgpu_n_cmem_portconflict++; //coal stalls aren't really a bank conflict, but this maintains previous behavior.
}
}
return accessq.empty(); //done if empty.
}
-mem_stage_stall_type tcache_check(shader_core_ctx_t *shader, mem_access_t& access){ /*done in process queue*/ return NO_RC_FAIL;}
-
-bool shader_memory_texture_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq,
- mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){
+bool shader_core_ctx::memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+{
+ // Process a single cycle of activity from the the texture memory queue.
- mem_stage_stall_type fail = shader_memory_generic_process_queue<tcache_check>(shader, 1, //how is tex memory banked?
- 1, //memory send max per cycle
- accessq );
+ std::vector<mem_access_t> &accessq = m_memory_queue.texture;
+ mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::tcache_check,
+ 1, //how is tex memory banked?
+ 1, //memory send max per cycle
+ accessq );
if (fail != NO_RC_FAIL){
rc_fail = fail; //keep other fails if this didn't fail.
fail_type = T_MEM;
@@ -2750,15 +2153,20 @@ bool shader_memory_texture_cycle( shader_core_ctx_t *shader, std::vector<mem_acc
}
-mem_stage_stall_type dcache_check(shader_core_ctx_t *shader, mem_access_t& access){
- if (access.cache_checked and not access.recheck_cache) return NO_RC_FAIL;
- if (!gpgpu_no_dl1 && !gpgpu_perfect_mem) {
+mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access)
+{
+ // Global memory (data cache) checks the cache for each access at the time it is processed.
+ // This is more accurate to hardware, and necessary for proper action of the writeback cache.
+
+ if (access.cache_checked and not access.recheck_cache)
+ return NO_RC_FAIL;
+ if (!m_config->gpgpu_no_dl1 && !m_config->gpgpu_perfect_mem) {
//check cache
- cache_request_status status = shd_cache_access_wb(shader->L1cache,
+ cache_request_status status = shd_cache_access_new(m_L1D,
access.addr,
WORD_SIZE, //this field is ignored.
access.iswrite,
- shader->gpu_cycle,
+ gpu_sim_cycle+gpu_tot_sim_cycle,
&access.wb_addr);
if (status == RESERVATION_FAIL) {
access.cache_checked = false;
@@ -2771,10 +2179,10 @@ mem_stage_stall_type dcache_check(shader_core_ctx_t *shader, mem_access_t& acces
//write has hit a reserved cache line
//it has writen its data into the cache line, so no need to go to memory
access.cache_hit = true;
- L1_write_hit_on_miss++;
+ m_stats->L1_write_hit_on_miss++;
// here we would search the MSHRs for the originating read,
// and mask off the writen bytes, so they are not overwritten in the cache when it comes back
- // --- don't actually do this since we are pretending.
+ // --- don't actually do this since we don't functionally execute based upon values in cache
// MSHR will still forward the unmasked value to its dependant reads.
// if doing stall on use, must stall this thread after this write (otherwise, inproper values may be forwarded to future reads).
}
@@ -2788,404 +2196,217 @@ mem_stage_stall_type dcache_check(shader_core_ctx_t *shader, mem_access_t& acces
access.cache_hit = false;
}
- if (gpgpu_perfect_mem) access.cache_hit = true;
+ if (m_config->gpgpu_perfect_mem) access.cache_hit = true;
- //atomics always go to memory
if (access.isatomic) {
- if (!gpgpu_perfect_mem) {
- access.cache_hit = false;
- } else {
- //unless perfect mem, in which case, the callback can only be done here
- dram_callback_t &atom_exec = shader->pipeline_reg[EX_MM][access.warp_indices[0]].callback;
+ 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);
+ } else {
+ // atomics always go to memory
+ access.cache_hit = false;
}
}
if (!access.cache_hit) {
- if (access.iswrite) L1_write_miss++;
- else L1_read_miss++;
+ if (access.iswrite) m_stats->L1_write_miss++;
+ else m_stats->L1_read_miss++;
}
return NO_RC_FAIL;
}
-bool shader_memory_global_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq,
- mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){
- mem_stage_stall_type fail = shader_memory_generic_process_queue<&dcache_check>(shader, gpgpu_cache_port_per_bank,
- 1, //memory send max per cycle
- accessq );
- if (fail != NO_RC_FAIL) {
- rc_fail = fail; //keep other fails if this didn't fail.
- //need to determine load/store, local/global:
- bool iswrite = accessq.back().iswrite;
- if (is_local(accessq.back().space)) {
- fail_type = (iswrite)?L_MEM_ST:L_MEM_LD;
- } else {
- fail_type = (iswrite)?G_MEM_ST:G_MEM_LD;
- }
+bool shader_core_ctx::memory_cycle( mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type)
+{
+ // Process a single cycle of activity from the the global/local memory queue.
- if (rc_fail == BK_CONF or rc_fail == COAL_STALL) {
- gpgpu_n_cache_bkconflict++;
- }
- }
- return accessq.empty(); //done if empty.
-}
+ std::vector<mem_access_t> &accessq = m_memory_queue.local_global;
+ mem_stage_stall_type stall_cond = process_memory_access_queue(&shader_core_ctx::dcache_check, m_config->gpgpu_cache_port_per_bank, 1, accessq);
-inline void mem_instruction_stats(inst_t* warp){
- //there must be a better way to count these
- for (unsigned i=0; i< (unsigned) pipe_simd_width; 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].op);
- switch (warp[i].space.get_type()) {
- case undefined_space:
- case reg_space:
- break;
- case shared_space:
- gpgpu_n_shmem_insn++;
- break;
- case const_space:
- gpgpu_n_const_insn++;
- break;
- case param_space_kernel:
- case param_space_local:
- gpgpu_n_param_insn++;
- break;
- case tex_space:
- gpgpu_n_tex_insn++;
- break;
- case global_space:
- case local_space:
- if (store){
- gpgpu_n_store_insn++;
- } else {
- gpgpu_n_load_insn++;
- }
- break;
- default:
- abort();
- }
+ if (stall_cond != NO_RC_FAIL) {
+ stall_reason = stall_cond;
+ bool iswrite = accessq.back().iswrite;
+ if (is_local(accessq.back().space))
+ access_type = (iswrite)?L_MEM_ST:L_MEM_LD;
+ else
+ access_type = (iswrite)?G_MEM_ST:G_MEM_LD;
+ if (stall_cond == BK_CONF or stall_cond == COAL_STALL)
+ m_stats->gpgpu_n_cache_bkconflict++;
}
+ return accessq.empty(); //done if empty.
}
-struct shader_queues_t{
- std::vector<mem_access_t> shared;
- std::vector<mem_access_t> constant;
- std::vector<mem_access_t> texture;
- std::vector<mem_access_t> global;
-};
-
-void shader_memory_queue(shader_core_ctx_t *shader, shader_queues_t *accessqs)
+void shader_core_ctx::memory_queue()
{
- //classify memory according to type;
- static unsigned char *path = NULL;
- if (!path) path = (unsigned char*)malloc(pipe_simd_width * sizeof(unsigned char));
- memset(path, 0, pipe_simd_width * sizeof(unsigned char));
- //static std::vector<char> path;
- //path.clear(); path.resize(p, NO_MEM_PATH);
-
- static unsigned type_counts[NUM_MEM_PATHS];
- memset(type_counts, 0, sizeof(type_counts));
- //static std::vector<unsigned> type_counts;
- //type_counts.clear(); type_counts.resize(NUM_MEM_PATHS);
-
- for (unsigned i=0; i< (unsigned) pipe_simd_width; i++) {
- if (shader->pipeline_reg[EX_MM][i].hw_thread_id == -1) continue; //bubble
- //this breaks some encapsulation: the is_[space] functions; if you change those, change this.
- switch (shader->pipeline_reg[EX_MM][i].space.get_type()) {
- case shared_space:
- path[i] = SHARED_MEM_PATH;
- type_counts[SHARED_MEM_PATH]++;
- break;
- case const_space:
- case param_space_kernel:
- path[i] = CONSTANT_MEM_PATH;
- type_counts[CONSTANT_MEM_PATH]++;
- break;
- case tex_space:
- path[i] = TEXTURE_MEM_PATH;
- type_counts[TEXTURE_MEM_PATH]++;
- break;
- case global_space:
- case local_space:
- case param_space_local:
- path[i] = GLOBAL_MEM_PATH;
- type_counts[GLOBAL_MEM_PATH]++;
- break;
- case param_space_unclassified:
- abort(); // todo: define access details
- break;
- default:
- break;
- }
- }
-
- //instruction counting:
- mem_instruction_stats(shader->pipeline_reg[EX_MM]);
-
-
- if (type_counts[SHARED_MEM_PATH]) shader_memory_shared_process_inst(shader, path, accessqs->shared);
- if (type_counts[CONSTANT_MEM_PATH]) shader_memory_const_process_inst(shader, path, accessqs->constant);
- if (type_counts[TEXTURE_MEM_PATH]) shader_memory_texture_process_inst(shader, path, accessqs->texture);
- if (type_counts[GLOBAL_MEM_PATH]) shader_memory_global_process_inst(shader, path, accessqs->global);
+ // 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]) )
+ 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()) {
+ 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;
+ case global_space: case local_space: case param_space_local: memory_global_process_warp(); break;
+ case param_space_unclassified: abort(); break;
+ default: break; // non-memory operations
+ }
}
-
-void shader_memory( shader_core_ctx_t *shader, unsigned int shader_number )
+void shader_core_ctx::memory()
{
- enum mem_stage_stall_type rc_fail = NO_RC_FAIL; // resource allocation
-
- //these should be local to the shader structure but can't because it is included in non c++ files.
- //so provide static storage for it here
- static std::vector<shader_queues_t> shader_memory_queues;
- if (shader_memory_queues.size() == 0) {
- shader_memory_queues.resize(gpu_n_shader);
- for (unsigned i = 0; i < gpu_n_shader; i++) {
- shader_memory_queues[i].shared.reserve(pipe_simd_width);
- shader_memory_queues[i].constant.reserve(pipe_simd_width);
- shader_memory_queues[i].texture.reserve(pipe_simd_width);
- shader_memory_queues[i].global.reserve(pipe_simd_width);
- }
- }
- shader_queues_t *accessqs = &(shader_memory_queues[shader->sid]);
-
- if (shader->shader_memory_new_instruction_processed == 0) {
- shader->shader_memory_new_instruction_processed = 1; //only do this once per pipeline occupant
- shader_memory_queue(shader, accessqs);
+ if (!m_shader_memory_new_instruction_processed) {
+ m_shader_memory_new_instruction_processed = true; // do once per warp instruction
+ memory_queue();
}
-
bool done = true;
+ enum mem_stage_stall_type rc_fail = NO_RC_FAIL;
mem_stage_access_type type;
+ done &= memory_shared_cycle(rc_fail, type);
+ done &= memory_constant_cycle(rc_fail, type);
+ done &= memory_texture_cycle(rc_fail, type);
+ done &= memory_cycle(rc_fail, type);
- done &= shader_memory_shared_cycle(shader, accessqs->shared, rc_fail, type);
- done &= shader_memory_constant_cycle(shader, accessqs->constant, rc_fail, type);
- done &= shader_memory_texture_cycle(shader, accessqs->texture, rc_fail, type);
- done &= shader_memory_global_cycle(shader, accessqs->global, rc_fail, type);
-
- //wb stalled?
- int wb_stalled = 0; // check if next stage is stalled
- for (unsigned i=0; i< (unsigned) pipe_simd_width; i++) {
- if (shader->pipeline_reg[MM_WB][i].hw_thread_id != -1 ) {
- wb_stalled = 1;
- break;
- }
- }
-
- if (!done) {
+ if (!done) { // log stall types and return
assert(rc_fail != NO_RC_FAIL);
- //log stall types
- gpu_stall_shd_mem++;
- gpu_stall_shd_mem_breakdown[type][rc_fail]++;
- }
-
- if (!done or wb_stalled) return;
-
- // this memory stage is done and not stalled by wb
- // pipeline forward
-
- check_stage_pcs(shader,EX_MM);
- // and pass instruction from EX_MM to MM_WB
- for (unsigned i=0; i< (unsigned) pipe_simd_width; i++) {
- if (shader->pipeline_reg[EX_MM][i].hw_thread_id == -1 )
- continue; // bubble
- shader->pipeline_reg[MM_WB][i] = shader->pipeline_reg[EX_MM][i];
- shader->pipeline_reg[MM_WB][i].mm_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
- shader->pipeline_reg[EX_MM][i] = nop_inst;
- }
-
- // reflect the change to EX|MM pipeline register to the pre_mem stage
- if (gpgpu_pre_mem_stages) {
- check_stage_pcs(shader,EX_MM);
- for (unsigned i=0;i< (unsigned)pipe_simd_width ;i++ )
- shader->pre_mem_pipeline[gpgpu_pre_mem_stages][i] = shader->pipeline_reg[EX_MM][i];
+ m_stats->gpu_stall_shd_mem++;
+ m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++;
+ return;
}
+ if( not pipeline_regster_empty( m_pipeline_reg[MM_WB] ) )
+ return; // writeback stalled
+ check_stage_pcs(EX_MM);
+ move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]);
}
-int writeback_l1_miss =0 ;
-
-
-void register_cta_thread_exit(shader_core_ctx_t *shader, int tid )
+void shader_core_ctx::register_cta_thread_exit(int tid )
{
- if (gpgpu_cuda_sim && gpgpu_spread_blocks_across_cores) {
- unsigned padded_cta_size = ptx_sim_cta_size();
- if (padded_cta_size%warp_size) {
- padded_cta_size = ((padded_cta_size/warp_size)+1)*(warp_size);
- }
- int cta_num = tid/padded_cta_size;
- assert( shader->cta_status[cta_num] > 0 );
- shader->cta_status[cta_num]--;
- if (!shader->cta_status[cta_num]) {
- shader->n_active_cta--;
- shader->deallocate_barrier(cta_num);
- shader_CTA_count_unlog(shader->sid, 1);
- printf("GPGPU-Sim uArch: Shader %d finished CTA #%d (%lld,%lld)\n", shader->sid, cta_num, gpu_sim_cycle, gpu_tot_sim_cycle );
- }
+ shader_core_ctx *shader = this;
+ unsigned padded_cta_size = m_gpu->the_kernel().threads_per_cta();
+ if (padded_cta_size%m_config->warp_size)
+ padded_cta_size = ((padded_cta_size/m_config->warp_size)+1)*(m_config->warp_size);
+ int cta_num = tid/padded_cta_size;
+ assert( shader->m_cta_status[cta_num] > 0 );
+ shader->m_cta_status[cta_num]--;
+ if (!shader->m_cta_status[cta_num]) {
+ shader->m_n_active_cta--;
+ shader->deallocate_barrier(cta_num);
+ shader_CTA_count_unlog(shader->m_sid, 1);
+ printf("GPGPU-Sim uArch: Shader %d finished CTA #%d (%lld,%lld)\n", shader->m_sid, cta_num, gpu_sim_cycle, gpu_tot_sim_cycle );
}
}
-void obtain_insn_latency_info(insn_latency_info *latinfo, inst_t *insn)
+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->ts_cycle;
- latinfo->ptx_thd_info = insn->ptx_thd_info;
+ latinfo->latency = gpu_tot_sim_cycle + gpu_sim_cycle - insn->issue_cycle;
}
int debug_tid = 0;
-unsigned gpu_n_max_mshr_writeback=1;
-void shader_writeback( shader_core_ctx_t *shader, unsigned int shader_number, int grid_num )
+void shader_core_ctx::writeback()
{
std::vector<inst_t> done_insts;
-
- static int *mshr_tid = NULL;
- static int *pl_tid = NULL;
-
std::vector<insn_latency_info> unlock_lat_infos;
- static insn_latency_info *mshr_lat_info = NULL;
- static insn_latency_info *pl_lat_info = NULL;
-
- mshr_entry *mshr_head = NULL;
-
- int tid;
- op_type op;
- int o1, o2, o3, o4;
- bool stalled_by_MSHR = false;
- bool writeback_by_MSHR = false;
bool w2rf = false;
+ memset(m_pl_tid,-1, sizeof(int)*m_config->warp_size);
+ check_stage_pcs(MM_WB);
- if ( mshr_tid == NULL ) {
- mshr_tid = (int*) malloc(sizeof(int)*pipe_simd_width);
- pl_tid = (int*) malloc(sizeof(int)*pipe_simd_width);
- mshr_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * pipe_simd_width);
- pl_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * pipe_simd_width);
- }
-
- memset(mshr_tid, -1, sizeof(int)*pipe_simd_width);
- memset(pl_tid, -1, sizeof(int)*pipe_simd_width);
-
-
- check_stage_pcs(shader,MM_WB);
-
- /* Generate Condition for instruction writeback to register file. */
- for (int i=0; i<pipe_simd_width; i++) {
- w2rf |= (shader->pipeline_reg[MM_WB][i].hw_thread_id >= 0);
- pl_tid[i] = shader->pipeline_reg[MM_WB][i].hw_thread_id;
+ // 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;
- for (unsigned i = 0; i < gpu_n_max_mshr_writeback; i++) {
- mshr_head = shader->mshr_unit->return_head();
- if (mshr_head) {
- //bail if we can't unlock anymore threads
- if (mshr_threads_unlocked + mshr_head->insts.size() > (unsigned) pipe_simd_width) break;
- assert(!gpgpu_strict_simd_wrbk);//implementation removed
- assert (mshr_head->insts.size());
- for (unsigned j = 0; j < mshr_head->insts.size(); j++) {
- inst_t &insn = mshr_head->insts[j];
+ 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(&mshr_lat_info[mshr_threads_unlocked], &(mshr_head->insts[j]));
- inflight_memory_insn_sub(shader, &mshr_head->insts[j]);
+ 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);
- shader->pending_mem_access--;
- // for ensuring that we don't unlock more than the code allows, needs to be fixed.
+ m_pending_mem_access--;
mshr_threads_unlocked++;
- }
- done_insts.insert(done_insts.end(), mshr_head->insts.begin(), mshr_head->insts.end());
+ 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);
- shader->mshr_unit->pop_return_head();
- writeback_by_MSHR = true;
- unlock_lat_infos.resize(mshr_threads_unlocked);
- std::copy(mshr_lat_info, mshr_lat_info + mshr_threads_unlocked, unlock_lat_infos.begin());
-
- if (w2rf) {
- stalled_by_MSHR = true;
- }
- assert(mshr_threads_unlocked);
- }
- }
- if (stalled_by_MSHR) {
- gpu_stall_by_MSHRwb++;
- }
-
- if (!writeback_by_MSHR) { //!writeback_by_MSHR
- memory_space_t warp_space = undefined_space;
-
- for (int i=0; i<pipe_simd_width; i++) {
- op = shader->pipeline_reg[MM_WB][i].op;
- tid = shader->pipeline_reg[MM_WB][i].hw_thread_id;
- o1 = shader->pipeline_reg[MM_WB][i].out[0];
- o2 = shader->pipeline_reg[MM_WB][i].out[1];
- o3 = shader->pipeline_reg[MM_WB][i].out[2];
- o4 = shader->pipeline_reg[MM_WB][i].out[3];
-
- obtain_insn_latency_info(&pl_lat_info[i], &shader->pipeline_reg[MM_WB][i]);
-
- // Collect threads that are done
- // Do not include cache misses for a writeback
- if(!shader->pipeline_reg[MM_WB][i].cache_miss) {
- if(shader->pipeline_reg[MM_WB][i].hw_thread_id > -1) {
- done_insts.push_back(shader->pipeline_reg[MM_WB][i]);
- unlock_lat_infos.push_back(pl_lat_info[i]);
- }
- }
+ 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);
+ }
- // All threads in the warp should have the same pc and space
- if(pl_tid[i] > -1 ) {
- warp_space = shader->pipeline_reg[MM_WB][i].space;
- }
+ if ( m_config->gpgpu_operand_collector )
+ stalled_by_MSHR = !m_operand_collector.writeback( m_pipeline_reg[MM_WB] );
- if(tid > -1) {
-/*
- if(!shader->pipeline_reg[MM_WB][i].cache_miss)
- printf("CACHE HIT sid=%d tid=%d pc=%d \n", shader->sid, tid, shader->pipeline_reg[MM_WB][i].pc);
- else
- printf("CACHE MISS sid=%d tid=%d pc=%d \n", shader->sid, tid, shader->pipeline_reg[MM_WB][i].pc);
-*/
- }
- }
+ 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)
- // Only need to unlock if warp is not empty
- if(w2rf)
- shader_queue_warp_unlocking(shader, pl_tid, warp_space, grid_num);
- }
+ // 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++;
- // Mark threads as done in warp tracker
for (unsigned i=0; i<done_insts.size(); i++) {
inst_t done_inst = done_insts[i];
-
- shader_call_thread_done(shader, grid_num, done_inst);
-
- // Statistics
- // At any rate, a real instruction is committed
- // - don't count cache miss
- gpu_sim_insn++;
+ call_thread_done(done_inst);
+
+ gpu_sim_insn++; // a (scalar) instruction is done
if ( !is_const(done_inst.space) )
- gpu_sim_insn_no_ld_const++;
- gpu_sim_insn_last_update = gpu_sim_cycle;
- shader->num_sim_insn++;
- shader->thread[done_inst.hw_thread_id].n_insn++;
- shader->thread[done_inst.hw_thread_id].n_insn_ac++;
+ m_stats->gpu_sim_insn_no_ld_const++;
+ m_gpu->gpu_sim_insn_last_update = gpu_sim_cycle;
+ 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(unlock_lat_infos[i].ptx_thd_info, pc, latency);
+ ptx_file_line_stats_add_latency(pc, latency);
}
-
}
- /* The pipeline can be stalled by MSHR */
- if (!stalled_by_MSHR) {
- for (int i=0; i<pipe_simd_width; i++) {
- shader->pipeline_reg[WB_RT][i] = shader->pipeline_reg[MM_WB][i];
- shader->pipeline_reg[MM_WB][i] = nop_inst;
+ 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 the delay queue for current cycle
- shader_process_delay_queue(shader);
+ process_delay_queue();
}
/*
@@ -3193,21 +2414,18 @@ void shader_writeback( shader_core_ctx_t *shader, unsigned int shader_number, in
*
* The amount of delay to add is determined by the instruction type.
*
- * @param *shader Pointer to shader core
* @param *tid Array of tid in the warp to unlock
- * @param pc Program counter for the current instruction in the warp
* @param space Address space for the current instruction in the warp
*
*/
-void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_space_t space, int grid_num) {
-
+void shader_core_ctx::queue_warp_unlocking(int *tids, const inst_t &inst )
+{
// Create a delay queue object and add it to the queue
- shader_core_ctx_t::fixeddelay_queue_warp_t fixeddelay_queue_warp;
-
- fixeddelay_queue_warp.grid_num = grid_num;
+ fixeddelay_queue_warp_t fixeddelay_queue_warp;
// Set ready_cycle based on instruction space
- switch(space.get_type()) {
+ 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;
@@ -3217,10 +2435,9 @@ void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_sp
}
// Store threads in delay queue warp object
- fixeddelay_queue_warp.tids.resize(warp_size);
- std::copy(tids, tids+warp_size, fixeddelay_queue_warp.tids.begin());
-
- shader->fixeddelay_queue.insert(fixeddelay_queue_warp);
+ 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);
}
/*
@@ -3229,22 +2446,23 @@ void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_sp
* @param *shader Pointer to shader core
*
*/
-void shader_process_delay_queue(shader_core_ctx_t *shader) {
+void shader_core_ctx::process_delay_queue() {
+ shader_core_ctx *shader=this;
// Unlock warps in fixeddelay_queue_warp
- std::multiset<shader_core_ctx_t::fixeddelay_queue_warp_t, shader_core_ctx_t::fixeddelay_queue_warp_comp>::iterator it;
- std::multiset<shader_core_ctx_t::fixeddelay_queue_warp_t, shader_core_ctx_t::fixeddelay_queue_warp_comp>::iterator it_last;
- for ( it=shader->fixeddelay_queue.begin() ;
- it != shader->fixeddelay_queue.end();
+ 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(!gpgpu_stall_on_use) {
+ 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<warp_size; i++) {
+ for(unsigned i=0; i<m_config->warp_size; i++) {
int tid = it->tids[i];
if(tid < 0) continue;
- if(get_warp_tracker_pool().wpt_thread_in_wpt(shader,tid)) {
+ if(m_warp_tracker->wpt_thread_in_wpt(tid)) {
skip_unlock = true;
break;
}
@@ -3255,12 +2473,24 @@ void shader_process_delay_queue(shader_core_ctx_t *shader) {
}
}
- // Unlock warp
- shader_unlock_warp(shader,it->tids, it->grid_num);
+ 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->fixeddelay_queue.erase(it_last);
+ shader->m_fixeddelay_queue.erase(it_last);
} else {
break;
}
@@ -3270,70 +2500,61 @@ void shader_process_delay_queue(shader_core_ctx_t *shader) {
/*
* Unlock a warp
*
- * @param *shd Pointer to shader core
* @param tids Vector of tid in the warp to unlock
*
*/
-void shader_unlock_warp(shader_core_ctx_t *shd, std::vector<int> tids, int grid_num) {
- int thd_unlocked = 0;
- int thd_exited = 0;
- int tid;
- int valid_tid = -1;
- // Unlock
- for (unsigned i=0; i<warp_size; i++) {
- tid = tids[i];
- if (tid >= 0) {
- valid_tid = tid;
- // thread completed if it is going to fetching beyond code boundary
- if ( gpgpu_cuda_sim && ptx_thread_done(shd->thread[tid].ptx_thd_info) ) {
- shd->not_completed -= 1;
- gpu_completed_thread += 1;
-
- int warp_id = wid_from_hw_tid(tid,warp_size);
- if (!(shd->warp[warp_id].n_completed < (unsigned)warp_size)) {
- printf("shader[%d]->warp[%d].n_completed = %d; warp_size = %d\n",
- shd->sid,warp_id, shd->warp[warp_id].n_completed, warp_size);
- }
- assert( shd->warp[warp_id].n_completed < (unsigned)warp_size );
- shd->warp[warp_id].n_completed++;
- if ( shd->model == NO_RECONVERGE ) {
- update_max_branch_priority(shd,warp_id,grid_num);
- }
-
- register_cta_thread_exit(shd, tid );
- thd_exited = 1;
-
- //printf("THREAD EXIT sid=%d tid=%d \n", shd->sid, tid);
-
- } else {
- shd->thread[tid].avail4fetch++;
- assert(shd->thread[tid].avail4fetch <= 1);
- assert( shd->warp[tid/warp_size].n_avail4fetch < warp_size );
- shd->warp[tid/warp_size].n_avail4fetch++;
- thd_unlocked = 1;
-
- //printf("THREAD UNLOCK sid=%d tid=%d \n", shd->sid, tid);
- }
- }
- }
-
- // Update warp was unlocked, update the warp active mask
- if(thd_unlocked || thd_exited) {
- // Update the warp active mask
- shader_pdom_update_warp_mask(shd, wid_from_hw_tid(valid_tid,warp_size));
- }
+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 (shd->model == POST_DOMINATOR || shd->model == NO_RECONVERGE) {
+ if (m_config->model == POST_DOMINATOR) {
// Do nothing
} else {
// For this case, submit to commit_queue
- if (shd->using_commit_queue && thd_unlocked) {
- int *tid_unlocked = alloc_commit_warp();
- std::copy(tids.begin(), tids.end(), tid_unlocked);
- dq_push(shd->thd_commit_queue,(void*)tid_unlocked);
- }
+ if (m_config->using_commit_queue && thd_unlocked)
+ m_thd_commit_queue->push( new std::vector<int>(tids), gpu_sim_cycle );
}
}
@@ -3342,93 +2563,73 @@ void shader_unlock_warp(shader_core_ctx_t *shd, std::vector<int> tids, int grid_
* 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 grid_num Grid number
* @param done_inst Completed instruction
*
*/
-void shader_call_thread_done( shader_core_ctx_t *shader, int grid_num, inst_t &done_inst ) {
-
- if (gpgpu_no_divg_load) {
-
- //printf("THREAD RETURNED sid=%d tid=%d pc=%d \n", shader->sid, done_inst.hw_thread_id, done_inst.pc);
-
+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( get_warp_tracker_pool().wpt_signal_avail(done_inst.hw_thread_id, shader, done_inst.pc) == 1 ) {
+ if( m_warp_tracker->wpt_signal_avail(done_inst.hw_thread_id, done_inst.pc) == 1 ) {
// Entire warp has returned
- //printf("WARP RETURNED sid=%d tid=%d pc=%d \n", shader->sid, done_inst.hw_thread_id, done_inst.pc);
-
// Deregister warp
- get_warp_tracker_pool().wpt_deregister_warp(done_inst.hw_thread_id, shader, done_inst.pc);
-
- // Signal scoreboard to release register
- shader->scrb->releaseRegisters( wid_from_hw_tid(done_inst.hw_thread_id, warp_size), &done_inst );
+ 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 shader_print_runtime_stat( FILE *fout ) {
- unsigned i;
-
+void gpgpu_sim::shader_print_runtime_stat( FILE *fout )
+{
fprintf(fout, "SHD_INSN: ");
- for (i=0;i<gpu_n_shader;i++) {
- fprintf(fout, "%u ",sc[i]->num_sim_insn);
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ fprintf(fout, "%u ",m_sc[i]->get_num_sim_insn());
fprintf(fout, "\n");
fprintf(fout, "SHD_THDS: ");
- for (i=0;i<gpu_n_shader;i++) {
- fprintf(fout, "%u ",sc[i]->not_completed);
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ fprintf(fout, "%u ",m_sc[i]->get_not_completed());
fprintf(fout, "\n");
fprintf(fout, "SHD_DIVG: ");
- for (i=0;i<gpu_n_shader;i++) {
- fprintf(fout, "%u ",sc[i]->n_diverge);
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ fprintf(fout, "%u ",m_sc[i]->get_n_diverge());
fprintf(fout, "\n");
fprintf(fout, "THD_INSN: ");
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- fprintf(fout, "%d ", sc[0]->thread[i].n_insn);
- }
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++)
+ fprintf(fout, "%d ", m_sc[0]->get_thread_n_insn(i) );
fprintf(fout, "\n");
}
-void shader_print_l1_miss_stat( FILE *fout ) {
- unsigned i;
-
+void gpgpu_sim::shader_print_l1_miss_stat( FILE *fout )
+{
fprintf(fout, "THD_INSN_AC: ");
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- fprintf(fout, "%d ", sc[0]->thread[i].n_insn_ac);
- }
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++)
+ fprintf(fout, "%d ", m_sc[0]->get_thread_n_insn_ac(i));
fprintf(fout, "\n");
-
fprintf(fout, "T_L1_Mss: "); //l1 miss rate per thread
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- fprintf(fout, "%d ", sc[0]->thread[i].n_l1_mis_ac);
- }
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++)
+ fprintf(fout, "%d ", m_sc[0]->get_thread_n_l1_mis_ac(i));
fprintf(fout, "\n");
-
fprintf(fout, "T_L1_Mgs: "); //l1 merged miss rate per thread
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- fprintf(fout, "%d ", sc[0]->thread[i].n_l1_mis_ac - sc[0]->thread[i].n_l1_mrghit_ac);
- }
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++)
+ fprintf(fout, "%d ", m_sc[0]->get_thread_n_l1_mis_ac(i) - m_sc[0]->get_thread_n_l1_mrghit_ac(i));
fprintf(fout, "\n");
-
fprintf(fout, "T_L1_Acc: "); //l1 access per thread
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- fprintf(fout, "%d ", sc[0]->thread[i].n_l1_access_ac);
- }
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++)
+ fprintf(fout, "%d ", m_sc[0]->get_thread_n_l1_access_ac(i));
fprintf(fout, "\n");
//per warp
int temp =0;
fprintf(fout, "W_L1_Mss: "); //l1 miss rate per warp
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- temp += sc[0]->thread[i].n_l1_mis_ac;
- if (i%warp_size == (unsigned)(warp_size-1)) {
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) {
+ temp += m_sc[0]->get_thread_n_l1_mis_ac(i);
+ if (i%m_shader_config->warp_size == (unsigned)(m_shader_config->warp_size-1)) {
fprintf(fout, "%d ", temp);
temp = 0;
}
@@ -3436,9 +2637,9 @@ void shader_print_l1_miss_stat( FILE *fout ) {
fprintf(fout, "\n");
temp=0;
fprintf(fout, "W_L1_Mgs: "); //l1 merged miss rate per warp
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- temp += (sc[0]->thread[i].n_l1_mis_ac - sc[0]->thread[i].n_l1_mrghit_ac);
- if (i%warp_size == (unsigned)(warp_size-1)) {
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) {
+ temp += (m_sc[0]->get_thread_n_l1_mis_ac(i) - m_sc[0]->get_thread_n_l1_mrghit_ac(i) );
+ if (i%m_shader_config->warp_size == (unsigned)(m_shader_config->warp_size-1)) {
fprintf(fout, "%d ", temp);
temp = 0;
}
@@ -3446,49 +2647,51 @@ void shader_print_l1_miss_stat( FILE *fout ) {
fprintf(fout, "\n");
temp =0;
fprintf(fout, "W_L1_Acc: "); //l1 access per warp
- for (i=0; i<gpu_n_thread_per_shader; i++) {
- temp += sc[0]->thread[i].n_l1_access_ac;
- if (i%warp_size == (unsigned)(warp_size-1)) {
+ for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) {
+ temp += m_sc[0]->get_thread_n_l1_access_ac(i);
+ if (i%m_shader_config->warp_size == (unsigned)(m_shader_config->warp_size-1)) {
fprintf(fout, "%d ", temp);
temp = 0;
}
}
fprintf(fout, "\n");
-
}
-void shader_print_warp( const shader_core_ctx_t *shader, inst_t *warp, FILE *fout, int stage_width, int print_mem, int mask )
+void shader_core_ctx::print_warp( inst_t *warp, FILE *fout, int print_mem, int mask ) const
{
- int i, j, warp_id = -1;
- for (i=0; i<stage_width; i++) {
+ 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 / warp_size;
+ warp_id = warp[i].hw_thread_id / m_config->warp_size;
break;
}
}
- i = (i>=stage_width)? 0 : i;
+ i = (i>=m_config->warp_size)? 0 : i;
- fprintf(fout,"0x%04x ", warp[i].pc );
+ 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<stage_width; j++)
+ 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<stage_width; j++)
+ 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 != -1 && shader->model == POST_DOMINATOR ) {
- pdom_warp_ctx_t *warp=&(shader->pdom_warp[warp_id]);
- if( warp->m_recvg_pc[warp->m_stack_top] == (unsigned)-1 ) {
- fprintf(fout," rp:--- ");
- } else {
- fprintf(fout," rp:0x%03x ", warp->m_recvg_pc[warp->m_stack_top] );
- }
+ 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 );
@@ -3501,62 +2704,64 @@ void shader_print_warp( const shader_core_ctx_t *shader, inst_t *warp, FILE *fou
fprintf(fout, "\n");
}
-void shader_print_stage(shader_core_ctx_t *shader, unsigned int stage,
- FILE *fout, int stage_width, int print_mem, int mask )
+void shader_core_ctx::print_stage(unsigned int stage, FILE *fout, int print_mem, int mask )
{
- inst_t *warp = shader->pipeline_reg[stage];
- shader_print_warp(shader,warp,fout,stage_width,print_mem,mask);
+ inst_t *warp = m_pipeline_reg[stage];
+ print_warp(warp,fout,print_mem,mask);
}
-void shader_print_pre_mem_stages(shader_core_ctx_t *shader, FILE *fout, int print_mem, int mask )
+void shader_core_ctx::print_pre_mem_stages( FILE *fout, int print_mem, int mask )
{
- int i, j;
+ unsigned i, j;
int warp_id;
- if (!gpgpu_pre_mem_stages) return;
+ if (!m_config->gpgpu_pre_mem_stages) return;
- for (unsigned pms = 0; pms <= gpgpu_pre_mem_stages - 1; pms++) {
- fprintf(fout, "PM[%01d] = ", pms);
+ for (unsigned pms = 0; pms <= m_config->gpgpu_pre_mem_stages; pms++) {
+ fprintf(fout, "PM[%01d] = ", pms);
warp_id = -1;
- for (i=0; i<pipe_simd_width; i++) {
- if (shader->pre_mem_pipeline[pms][i].hw_thread_id > -1) {
- warp_id = shader->pre_mem_pipeline[pms][i].hw_thread_id / warp_size;
+ 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>=pipe_simd_width)? 0 : i;
+ i = (i>=m_config->warp_size)? 0 : i;
- fprintf(fout,"0x%04x ", shader->pre_mem_pipeline[pms][i].pc );
+ 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<pipe_simd_width; j++)
- fprintf(fout, "%03d ", shader->pre_mem_pipeline[pms][j].hw_thread_id);
+ 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<pipe_simd_width; j++)
- fprintf(fout, "%c", ((shader->pre_mem_pipeline[pms][j].hw_thread_id != -1)?'1':'0') );
+ 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 && shader->model == POST_DOMINATOR ) {
- pdom_warp_ctx_t *warp=&(shader->pdom_warp[warp_id]);
- if( warp->m_recvg_pc[warp->m_stack_top] == (unsigned)-1 ) {
- printf(" rp:--- ");
- } else {
- printf(" rp:0x%03x ", warp->m_recvg_pc[warp->m_stack_top] );
- }
+ 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( shader->pre_mem_pipeline[pms][i].pc, fout );
+ ptx_print_insn( pre_mem_pipeline[pms][i].pc, fout );
if( mask & 0x10 ) {
- if ( ( shader->pre_mem_pipeline[pms][i].op == LOAD_OP ||
- shader->pre_mem_pipeline[pms][i].op == STORE_OP ) && print_mem )
- fprintf(fout, " mem: 0x%016llx", shader->pre_mem_pipeline[pms][i].memreqaddr);
+ 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");
}
@@ -3564,158 +2769,134 @@ void shader_print_pre_mem_stages(shader_core_ctx_t *shader, FILE *fout, int prin
const char * ptx_get_fname( unsigned PC );
-void shader_display_pipeline(shader_core_ctx_t *shader, FILE *fout, int print_mem, int mask )
+void shader_core_ctx::display_pdom_state(FILE *fout, int mask )
{
- // call this function from within gdb to print out status of pipeline
- // if you encounter a bug, or to visualize pipeline operation
- // (this is a good way to "verify" your pipeline model makes sense!)
+ if ( (mask & 4) && m_config->model == POST_DOMINATOR ) {
+ fprintf(fout,"warp status:\n");
+ unsigned n = m_config->n_thread_per_shader / m_config->warp_size;
+ for (unsigned i=0; i < n; i++) {
+ unsigned nactive = 0;
+ for (unsigned j=0; j<m_config->warp_size; j++ ) {
+ unsigned tid = i*m_config->warp_size + j;
+ 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 );
+ if ( done_cycle ) {
+ printf("\n w%02u:t%03u: done @ cycle %u", i, tid, done_cycle );
+ }
+ }
+ }
+ if ( nactive == 0 ) {
+ continue;
+ }
+ m_pdom_warp[i]->print(fout);
+ }
+ fprintf(fout,"\n");
+ }
+}
+void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask )
+{
fprintf(fout, "=================================================\n");
- fprintf(fout, "shader %u at cycle %Lu+%Lu (%u threads running)\n", shader->sid,
- gpu_tot_sim_cycle, gpu_sim_cycle, shader->not_completed);
+ fprintf(fout, "shader %u at cycle %Lu+%Lu (%u threads running)\n", m_sid,
+ gpu_tot_sim_cycle, gpu_sim_cycle, m_not_completed);
fprintf(fout, "=================================================\n");
- if ( (mask & 4) && shader->model == POST_DOMINATOR ) {
- fprintf(fout,"warp status:\n");
- unsigned n = shader->n_threads / warp_size;
- for (unsigned i=0; i < n; i++) {
- unsigned nactive = 0;
- for (unsigned j=0; j<warp_size; j++ ) {
- unsigned tid = i*warp_size + j;
- int done = ptx_thread_done( shader->thread[tid].ptx_thd_info );
- nactive += (ptx_thread_done( shader->thread[tid].ptx_thd_info )?0:1);
- if ( done && (mask & 8) ) {
- unsigned done_cycle = ptx_thread_donecycle( shader->thread[tid].ptx_thd_info );
- if ( done_cycle ) {
- printf("\n w%02u:t%03u: done @ cycle %u", i, tid, done_cycle );
- }
- }
- }
- if ( nactive == 0 ) {
- continue;
- }
- pdom_warp_ctx_t *warp=&(shader->pdom_warp[i]);
- for ( int k=0; k <= warp->m_stack_top; k++ ) {
- if ( k==0 ) {
- fprintf(fout, "w%02d (%2u thds active): %2u ", i, nactive, k );
- } else {
- fprintf(fout, " %2u ", k );
- }
- for (unsigned m=1,j=0; j<warp_size; j++, m<<=1)
- fprintf(fout, "%c", ((warp->m_active_mask[k] & m)?'1':'0') );
- fprintf(fout, " pc: %4u", warp->m_pc[k] );
- if ( warp->m_recvg_pc[k] == (unsigned)-1 ) {
- fprintf(fout," rp: ---- cd: %2u ", warp->m_calldepth[k] );
- } else {
- fprintf(fout," rp: %4u cd: %2u ", warp->m_recvg_pc[k], warp->m_calldepth[k] );
- }
- if ( warp->m_branch_div_cycle[k] != 0 ) {
- fprintf(fout," bd@%6u ", (unsigned) warp->m_branch_div_cycle[k] );
- } else {
- fprintf(fout," " );
- }
- //fprintf(fout," func=\'%s\' ", ptx_get_fname( warp->m_pc[k] ) );
- ptx_print_insn( warp->m_pc[k], fout );
- fprintf(fout,"\n");
- }
- }
- fprintf(fout,"\n");
- }
-
- if ( mask & 0x20 ) {
- fprintf(fout, "TS/IF = ");
- shader_print_stage(shader, TS_IF, fout, warp_size, print_mem, mask);
- }
+ if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) )
+ display_pdom_state(fout,mask);
- fprintf(fout, "IF/ID = ");
- shader_print_stage(shader, IF_ID, fout, pipe_simd_width, print_mem, mask );
+ if (!strcmp("GT200",m_config->pipeline_model) ) {
+ dump_istream_state(fout);
+ fprintf(fout,"\n");
- if (gpgpu_operand_collector)
- shader->m_opndcoll_new.dump(fout);
-
- if (shader->using_rrstage) {
- fprintf(fout, "ID/RR = ");
- shader_print_stage(shader, ID_RR, fout, pipe_simd_width, print_mem, mask);
+ fprintf(fout, "IF/ID = ");
+ if( !m_inst_fetch_buffer.m_valid )
+ fprintf(fout,"bubble\n");
+ else {
+ fprintf(fout,"w%2u : pc = 0x%x, nbytes = %u\n",
+ m_inst_fetch_buffer.m_warp_id,
+ m_inst_fetch_buffer.m_pc,
+ m_inst_fetch_buffer.m_nbytes );
+ }
+ fprintf(fout,"\nibuffer status:\n");
+ for( unsigned i=0; i<m_config->max_warps_per_shader; i++) {
+ if( !m_warp[i].ibuffer_empty() )
+ m_warp[i].print_ibuffer(fout);
+ }
+ fprintf(fout,"\n");
+ display_pdom_state(fout,mask);
}
- fprintf(fout, "ID/EX = ");
- shader_print_stage(shader, ID_EX, fout, pipe_simd_width, print_mem, mask);
-
- shader_print_pre_mem_stages(shader, fout, print_mem, mask);
+ m_scoreboard->printContents();
- if (!gpgpu_pre_mem_stages)
- fprintf(fout, "EX/MEM= ");
+ if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) {
+ if ( mask & 0x20 ) {
+ fprintf(fout, "TS/IF = ");
+ print_stage(TS_IF, fout, print_mem, mask);
+ }
+ fprintf(fout, "IF/ID = ");
+ print_stage(IF_ID, fout, print_mem, mask );
+ }
+ if (m_config->gpgpu_operand_collector) {
+ fprintf(fout,"ID/OC (SP) = ");
+ print_stage(ID_OC, fout, print_mem, mask);
+ fprintf(fout,"ID/OC (SFU) = ");
+ 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, "PM/MEM= ");
- shader_print_stage(shader, EX_MM, fout, pipe_simd_width, print_mem, mask);
-
- fprintf(fout, "MEM/WB= ");
- shader_print_stage(shader, MM_WB, fout, pipe_simd_width, print_mem, mask);
-
- fprintf(fout, "\n");
-}
-
-void shader_dump_thread_state(shader_core_ctx_t *shader, FILE *fout )
-{
- fprintf( fout, "\n");
- for ( unsigned w = 0; w < gpu_n_thread_per_shader/warp_size; w++ ) {
- int tid = w*warp_size;
- if ( shader->warp[w].n_completed < (unsigned)warp_size ) {
- fprintf( fout, " %u:%3u fetch state = c:%u a4f:%u bw:%u (completed: ", shader->sid, tid,
- shader->warp[w].n_completed,
- shader->warp[w].n_avail4fetch,
- shader->warp[w].n_waiting_at_barrier );
-
- for ( unsigned i = tid; i < (w+1)*warp_size; i++ ) {
- if ( gpgpu_cuda_sim && ptx_thread_done(shader->thread[i].ptx_thd_info) ) {
- fprintf(fout,"1");
- } else {
- fprintf(fout,"0");
- }
- if ( (((i+1)%4) == 0) && (i+1) < (w+1)*warp_size ) {
- fprintf(fout,",");
- }
- }
- fprintf(fout,")\n");
- }
+ 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 = ");
+ print_stage(EX_MM, fout, print_mem, mask);
+ fprintf(fout, "MEM/WB = ");
+ print_stage(MM_WB, fout, print_mem, mask);
+ fprintf(fout, "\n");
+ mshr_print(fout,0);
}
-void shader_dp(shader_core_ctx_t *shader, int print_mem) {
- shader_display_pipeline(shader, stdout, print_mem, 7 );
-}
-
-
-unsigned int max_cta_per_shader( shader_core_ctx_t *shader)
+unsigned int shader_core_ctx::max_cta( class function_info *kernel )
{
- unsigned int result;
unsigned int padded_cta_size;
- padded_cta_size = ptx_sim_cta_size();
- if (padded_cta_size%warp_size) {
- padded_cta_size = ((padded_cta_size/warp_size)+1)*(warp_size);
- //printf("padded_cta_size=%u\n", padded_cta_size);
- }
+ padded_cta_size = m_gpu->the_kernel().threads_per_cta();
+ if (padded_cta_size%m_config->warp_size)
+ padded_cta_size = ((padded_cta_size/m_config->warp_size)+1)*(m_config->warp_size);
//Limit by n_threads/shader
- unsigned int result_thread = shader->n_threads / padded_cta_size;
+ unsigned int result_thread = m_config->n_thread_per_shader / padded_cta_size;
- const struct gpgpu_ptx_sim_kernel_info *kernel_info = ptx_sim_kernel_info();
+ const struct gpgpu_ptx_sim_kernel_info *kernel_info = ptx_sim_kernel_info(kernel);
//Limit by shmem/shader
unsigned int result_shmem = (unsigned)-1;
if (kernel_info->smem > 0)
- result_shmem = shader->shmem_size / kernel_info->smem;
+ result_shmem = m_config->gpgpu_shmem_size / kernel_info->smem;
//Limit by register count, rounded up to multiple of 4.
unsigned int result_regs = (unsigned)-1;
if (kernel_info->regs > 0)
- result_regs = shader->n_registers / (padded_cta_size * ((kernel_info->regs+3)&~3));
+ result_regs = m_config->gpgpu_shader_registers / (padded_cta_size * ((kernel_info->regs+3)&~3));
//Limit by CTA
- unsigned int result_cta = shader->n_cta;
+ unsigned int result_cta = m_config->max_cta_per_core;
- result = result_thread;
+ unsigned result = result_thread;
result = gs_min2(result, result_shmem);
result = gs_min2(result, result_regs);
result = gs_min2(result, result_cta);
@@ -3732,114 +2913,49 @@ unsigned int max_cta_per_shader( shader_core_ctx_t *shader)
}
if (result < 1) {
- printf ("Error: max_cta_per_shader(\"%s\") returning %d. Kernel requires more resources than shader has?\n", shader->name, result);
+ printf ("Error: max_cta_per_shader(\"%s\") returning %d. Kernel requires more resources than shader has?\n", m_name, result);
abort();
}
return result;
}
-void shader_cycle( shader_core_ctx_t *shader,
- unsigned int shader_number,
- int grid_num )
+void shader_core_ctx::cycle_gt200()
{
- if (gpgpu_operand_collector)
- shader_opnd_collect_write(shader);
- shader_writeback(shader, shader_number, grid_num);
- shader_memory(shader, shader_number);
- if (gpgpu_pre_mem_stages) // for modeling deeper pipelines
- shader_pre_memory(shader, shader_number);
- shader_execute(shader, shader_number);
- if (shader->using_rrstage) {
- // Model register bank conflicts as in
- // Fung et al. MICRO'07 / ACM TACO'09 papers.
- shader_preexecute (shader, shader_number);
- }
- if (gpgpu_operand_collector)
- shader_opnd_collect_read(shader);
- shader_decode (shader, shader_number, grid_num);
- shader_fetch (shader, shader_number, grid_num);
+ clear_stage(m_pipeline_reg[WB_RT]);
+ writeback();
+ memory();
+ execute();
+ m_operand_collector.step(m_pipeline_reg[ID_OC],m_pipeline_reg[ID_OC_SFU]);
+ decode_new();
+ fetch_new();
}
-// performance counter that are not local to one shader
-void shader_print_accstats( FILE* fout )
+void shader_core_ctx::cycle()
{
- fprintf(fout, "gpgpu_n_load_insn = %d\n", gpgpu_n_load_insn);
- fprintf(fout, "gpgpu_n_store_insn = %d\n", gpgpu_n_store_insn);
- fprintf(fout, "gpgpu_n_shmem_insn = %d\n", gpgpu_n_shmem_insn);
- fprintf(fout, "gpgpu_n_tex_insn = %d\n", gpgpu_n_tex_insn);
- fprintf(fout, "gpgpu_n_const_mem_insn = %d\n", gpgpu_n_const_insn);
- fprintf(fout, "gpgpu_n_param_mem_insn = %d\n", gpgpu_n_param_insn);
-
- fprintf(fout, "gpgpu_n_shmem_bkconflict = %d\n", gpgpu_n_shmem_bkconflict);
- fprintf(fout, "gpgpu_n_cache_bkconflict = %d\n", gpgpu_n_cache_bkconflict);
-
- fprintf(fout, "gpgpu_n_intrawarp_mshr_merge = %d\n", gpgpu_n_intrawarp_mshr_merge);
- fprintf(fout, "gpgpu_n_cmem_portconflict = %d\n", gpgpu_n_cmem_portconflict);
-
- fprintf(fout, "gpgpu_n_writeback_l1_miss = %d\n", writeback_l1_miss);
-
- fprintf(fout, "gpgpu_n_partial_writes = %d\n", gpgpu_n_partial_writes);
-
- fprintf(fout, "gpgpu_stall_shd_mem[c_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][BK_CONF]);
- fprintf(fout, "gpgpu_stall_shd_mem[c_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][MSHR_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[c_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[t_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][MSHR_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[t_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[s_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[S_MEM][BK_CONF]);
- fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][bk_conf] = %d\n",
- gpu_stall_shd_mem_breakdown[G_MEM_LD][BK_CONF] +
- gpu_stall_shd_mem_breakdown[G_MEM_ST][BK_CONF] +
- gpu_stall_shd_mem_breakdown[L_MEM_LD][BK_CONF] +
- gpu_stall_shd_mem_breakdown[L_MEM_ST][BK_CONF]
- ); // coalescing stall at data cache
- fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][coal_stall] = %d\n",
- gpu_stall_shd_mem_breakdown[G_MEM_LD][COAL_STALL] +
- gpu_stall_shd_mem_breakdown[G_MEM_ST][COAL_STALL] +
- gpu_stall_shd_mem_breakdown[L_MEM_LD][COAL_STALL] +
- gpu_stall_shd_mem_breakdown[L_MEM_ST][COAL_STALL]
- ); // coalescing stall + bank conflict at data cache
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][MSHR_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_CACHE_RSRV_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][MSHR_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_CACHE_RSRV_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][MSHR_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_CACHE_RSRV_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][MSHR_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_ICNT_RC_FAIL]);
- fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_CACHE_RSRV_FAIL]);
-
- fprintf(fout, "gpu_reg_bank_conflict_stalls = %d\n", gpu_reg_bank_conflict_stalls);
-
- if (warp_occ_detailed) {
- int n_warp = gpu_n_thread_per_shader / warp_size;
-
- for (unsigned s = 0; s<gpu_n_shader; s++)
- for (int w = 0; w<n_warp; w++) {
- fprintf(fout, "wod[%d][%d]=", s, w);
- for (unsigned t = 0; t<warp_size; t++) {
- fprintf(fout, "%d ", warp_occ_detailed[s * n_warp + w][t]);
- }
- fprintf(fout, "\n");
- }
+ 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_cache_flush(shader_core_ctx_t* sc)
+void shader_core_ctx::cache_flush()
{
unsigned int i;
unsigned int set;
unsigned long long int flush_addr;
- shd_cache_t *cp = sc->L1cache;
+ shd_cache_t *cp = m_L1D;
shd_cache_line_t *pline;
for (i=0; i<cp->nset*cp->assoc; i++) {
@@ -3848,7 +2964,7 @@ void shader_cache_flush(shader_core_ctx_t* sc)
if ((pline->status & (DIRTY|VALID)) == (DIRTY|VALID)) {
flush_addr = pline->addr;
- sc->fq_push(flush_addr, sc->L1cache->line_sz, 1, NO_PARTIAL_WRITE, sc->sid, 0, NULL, 0, GLOBAL_ACC_W, -1);
+ fq_push(flush_addr, m_L1D->line_sz, 1, NO_PARTIAL_WRITE, 0, NULL, 0, GLOBAL_ACC_W, -1);
pline->status &= ~VALID;
pline->status &= ~DIRTY;
@@ -3889,15 +3005,22 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads()
_outmatch[j] = -1;
for( unsigned i=0; i<m_num_banks; i++) {
- for( unsigned j=0; j<m_num_collectors; j++)
+ for( unsigned j=0; j<m_num_collectors; j++) {
+ assert( i < (unsigned)_inputs );
+ assert( j < (unsigned)_outputs );
_request[i][j] = 0;
+ }
if( !m_queue[i].empty() ) {
const op_t &op = m_queue[i].front();
int oc_id = op.get_oc_id();
+ assert( i < (unsigned)_inputs );
+ assert( oc_id < _outputs );
_request[i][oc_id] = 1;
}
- if( m_allocated_bank[i].is_write() )
+ if( m_allocated_bank[i].is_write() ) {
+ assert( i < (unsigned)_inputs );
_inmatch[i] = 0; // write gets priority
+ }
}
///// wavefront allocator from booksim... --->
@@ -3914,7 +3037,9 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads()
( _outmatch[output] == -1 ) &&
( _request[input][output]/*.label != -1*/ ) ) {
// Grant!
+ assert( input < _inputs );
_inmatch[input] = output;
+ assert( output < _outputs );
_outmatch[output] = input;
}
@@ -3939,24 +3064,6 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads()
}
}
-
-/*
- for( unsigned c=0; c < m_num_collectors; c++ ) {
- unsigned cu = (m_last_cu+c+1)%m_num_collectors;
- for( unsigned b=0; b < m_num_banks; b++ ) {
- unsigned bank = (m_allocator_rr_head[cu]+b+1)%m_num_banks;
- if( (!m_queue[bank].empty()) && m_allocated_bank[bank].is_free() ) {
- op_t &op = m_queue[bank].front();
- result.push_back(op);
- m_allocated_bank[bank].alloc_read(op);
- m_queue[bank].pop_front();
- m_allocator_rr_head[cu] = bank;
- m_last_cu = cu;
- break; // skip to next collector unit
- }
- }
- }
-*/
return result;
}
@@ -4042,7 +3149,7 @@ void barrier_set_t::warp_exit( unsigned warp_id )
}
// assertions
-bool barrier_set_t::warp_waiting_at_barrier( unsigned warp_id )
+bool barrier_set_t::warp_waiting_at_barrier( unsigned warp_id ) const
{
return m_warp_at_barrier.test(warp_id);
}
@@ -4075,11 +3182,37 @@ void shader_core_ctx::warp_exit( unsigned warp_id )
m_barriers.warp_exit( warp_id );
}
-bool shader_core_ctx::warp_waiting_at_barrier( unsigned warp_id )
+bool shader_core_ctx::warp_waiting_at_barrier( unsigned warp_id ) const
{
return m_barriers.warp_waiting_at_barrier(warp_id);
}
+void shader_core_ctx::set_at_memory_barrier( unsigned warp_id )
+{
+ m_warp[warp_id].set_membar();
+}
+
+bool shader_core_ctx::warp_waiting_at_mem_barrier( unsigned warp_id )
+{
+ if( !m_warp[warp_id].get_membar() )
+ return false;
+ if( !m_scoreboard->pendingWrites(warp_id) ) {
+ m_warp[warp_id].clear_membar();
+ return false;
+ }
+ return true;
+}
+
+bool shader_core_ctx::warp_waiting_for_atomics( unsigned warp_id ) const
+{
+ return m_warp[warp_id].get_n_atomic()>0;
+}
+
+gpgpu_sim *shader_core_ctx::get_gpu()
+{
+ return m_gpu;
+}
+
void shader_core_ctx::allocate_barrier( unsigned cta_id, warp_set_t warps )
{
m_barriers.allocate_barrier(cta_id,warps);
@@ -4090,36 +3223,384 @@ void shader_core_ctx::deallocate_barrier( unsigned cta_id )
m_barriers.deallocate_barrier(cta_id);
}
+void shader_core_ctx::decrement_atomic_count( unsigned wid )
+{
+ assert( m_warp[wid].get_n_atomic() > 0 );
+ m_warp[wid].dec_n_atomic();
+}
+
+bool shd_warp_t::done()
+{
+ return get_n_completed() == m_warp_size;
+}
+
+bool shd_warp_t::waiting()
+{
+ if ( done() ) {
+ // waiting to be initialized with a kernel
+ return true;
+ } else if ( m_shader->warp_waiting_at_barrier(m_warp_id) ) {
+ // waiting for other warps in CTA to reach barrier
+ return true;
+ } else if ( m_shader->warp_waiting_at_mem_barrier(m_warp_id) ) {
+ // waiting for memory barrier
+ return true;
+ } else if ( m_shader->warp_waiting_for_atomics(m_warp_id) ) {
+ // waiting for atomic operation to complete at memory:
+ // this stall is not required for accurate timing model, but rather we
+ // stall here since if a call/return instruction occurs in the meantime
+ // the functional execution of the atomic when it hits DRAM can cause
+ // the wrong register to be read.
+ return true;
+ }
+ return false;
+}
+
+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: ",
+ m_warp_id,
+ m_next_pc,
+ n_completed,
+ n_avail4fetch,
+ m_inst_in_pipeline,
+ m_stores_outstanding,
+ m_n_atomic,
+ n_waiting_at_barrier );
+ 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");
+ if ( (((i+1)%4) == 0) && (i+1) < (m_warp_id+1)*m_warp_size )
+ fprintf(fout,",");
+ }
+ fprintf(fout,") ");
+ fprintf(fout," last fetched @ %5llu", m_last_fetch);
+ if( m_imiss_pending )
+ fprintf(fout," i-miss pending");
+ fprintf(fout,"\n");
+ }
+}
+
+void shd_warp_t::print_ibuffer( FILE *fout ) const
+{
+ fprintf(fout," ibuffer[%2u] : ", m_warp_id );
+ for( unsigned i=0; i < IBUFFER_SIZE; i++) {
+ const inst_t *inst = m_ibuffer[i];
+ if( inst ) inst->print_insn(fout);
+ else fprintf(fout," <empty> ");
+ }
+ fprintf(fout,"\n");
+}
+
+pdom_warp_ctx_t::pdom_warp_ctx_t( unsigned wid, class shader_core_ctx *shdr )
+{
+ m_warp_id=wid;
+ m_shader=shdr;
+ m_warp_size=m_shader->get_config()->warp_size;
+ m_stack_top = 0;
+ m_pc = (address_type*)calloc(m_warp_size * 2, sizeof(address_type));
+ m_calldepth = (unsigned int*)calloc(m_warp_size * 2, sizeof(unsigned int));
+ m_active_mask = (unsigned int*)calloc(m_warp_size * 2, sizeof(unsigned int));
+ m_recvg_pc = (address_type*)calloc(m_warp_size * 2, sizeof(address_type));
+ m_branch_div_cycle = (unsigned long long *)calloc(m_warp_size * 2, sizeof(unsigned long long ));
+ reset();
+}
+
+void pdom_warp_ctx_t::reset()
+{
+ m_stack_top = 0;
+ memset(m_pc, -1, m_warp_size * 2 * sizeof(address_type));
+ memset(m_calldepth, 0, m_warp_size * 2 * sizeof(unsigned int));
+ memset(m_active_mask, 0, m_warp_size * 2 * sizeof(unsigned int));
+ memset(m_recvg_pc, -1, m_warp_size * 2 * sizeof(address_type));
+ memset(m_branch_div_cycle, 0, m_warp_size * 2 * sizeof(unsigned long long ));
+}
+
+void pdom_warp_ctx_t::launch( address_type start_pc, unsigned active_mask )
+{
+ reset();
+ m_pc[0] = start_pc;
+ m_calldepth[0] = 1;
+ m_active_mask[0] = active_mask;
+}
+
+unsigned pdom_warp_ctx_t::get_active_mask() const
+{
+ return m_active_mask[m_stack_top];
+}
+
+void mshr_entry::init( new_addr_type address, bool wr, memory_space_t space, unsigned warp_id )
+{
+ static unsigned next_request_uid = 1;
+ m_request_uid = next_request_uid++;
+ m_status = INITIALIZED;
+ m_addr = address;
+ m_mf = NULL;
+ m_merged_on_other_reqest = false;
+ m_merged_requests =NULL;
+ m_iswrite = wr;
+ m_isinst = space==instruction_space;
+ m_islocal = is_local(space);
+ m_isconst = is_const(space);
+ m_istexture = space==tex_space;
+ m_insts.clear();
+ m_warp_id = warp_id;
+}
+
+void mshr_entry::set_status( enum mshr_status status )
+{
+ mshr_entry * req = this;
+ while (req) {
+ req->m_status = status;
+ req = req->m_merged_requests;
+ }
+#if DEBUGL1MISS
+ printf("cycle %d Addr %x %d \n",gpu_sim_cycle,CACHE_TAG_OF_64(m_addr),status);
+#endif
+}
+
+void mshr_entry::print(FILE *fp, unsigned mask) const
+{
+ if ( mask & 0x100 ) {
+ fprintf(fp, "MSHR(%u): w%2u req uid=%5u, %s (0x%llx) merged:%d status:%s ",
+ m_id,
+ m_warp_id,
+ m_request_uid,
+ (m_iswrite)? "store" : "load ",
+ m_addr,
+ (m_merged_requests != NULL || m_merged_on_other_reqest),
+ MSHR_Status_str[m_status]);
+ if ( m_mf )
+ ptx_print_insn( m_mf->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);
+ }
+ }
+ }
+}
+
void opndcoll_rfu_t::init( unsigned num_collectors_alu,
unsigned num_collectors_sfu,
unsigned num_banks,
- const shader_core_ctx *shader )
+ shader_core_ctx *shader,
+ inst_t **alu_port,
+ inst_t **sfu_port )
{
- unsigned num_alu_cu = gpgpu_operand_collector_num_units;
- unsigned num_sfu_cu = gpgpu_operand_collector_num_units_sfu;
- m_num_collectors = num_alu_cu+num_sfu_cu;
+ m_num_collectors = num_collectors_alu+num_collectors_sfu;
m_shader=shader;
m_arbiter.init(m_num_collectors,num_banks);
- m_alu_port = shader->pipeline_reg[ID_EX];
- m_sfu_port = shader->pipeline_reg[OC_EX_SFU];
+ m_alu_port = alu_port;
+ m_sfu_port = sfu_port;
- m_dispatch_units[ m_alu_port ].init( num_alu_cu );
- m_dispatch_units[ m_sfu_port ].init( num_sfu_cu );
+ m_dispatch_units[ m_alu_port ].init( num_collectors_alu );
+ m_dispatch_units[ m_sfu_port ].init( num_collectors_sfu );
m_num_banks = num_banks;
+
+ m_bank_warp_shift = 0;
+ m_warp_size = shader->get_config()->warp_size;
+ m_bank_warp_shift = (unsigned)(int) (log(m_warp_size+0.5) / log(2.0));
+ assert( (m_bank_warp_shift == 5) || (m_warp_size != 32) );
+
m_cu = new collector_unit_t[m_num_collectors];
unsigned c=0;
- for(; c<num_alu_cu; c++) {
- m_cu[c].init(c,m_alu_port);
+ for(; c<num_collectors_alu; c++) {
+ m_cu[c].init(c,m_alu_port,num_banks,m_bank_warp_shift,m_warp_size,this);
m_free_cu[m_alu_port].push_back(&m_cu[c]);
m_dispatch_units[m_alu_port].add_cu(&m_cu[c]);
}
for(; c<m_num_collectors; c++) {
- m_cu[c].init(c,m_sfu_port);
+ m_cu[c].init(c,m_sfu_port,num_banks,m_bank_warp_shift,m_warp_size,this);
m_free_cu[m_sfu_port].push_back(&m_cu[c]);
m_dispatch_units[m_sfu_port].add_cu(&m_cu[c]);
}
}
+
+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 bank = regnum;
+ if (bank_warp_shift)
+ bank += tid >> bank_warp_shift;
+ return bank % num_banks;
+}
+
+bool opndcoll_rfu_t::writeback( const inst_t &fvt )
+{
+ int tid = fvt.hw_thread_id;
+ assert( tid >= 0 ); // must be a valid instruction
+ std::list<unsigned> regs = m_shader->get_regs_written(fvt);
+ 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);
+ if( m_arbiter.bank_idle(bank) ) {
+ m_arbiter.allocate_bank_for_write(bank,op_t(&fvt,reg,m_num_banks,m_bank_warp_shift));
+ } else {
+ return false;
+ }
+ last_reg=reg;
+ }
+ return true;
+}
+
+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) )
+ continue;
+ dispatch_unit_t &du = p->second;
+ collector_unit_t *cu = du.find_ready();
+ if( cu ) {
+ cu->dispatch();
+ m_free_cu[port].push_back(cu);
+ }
+ }
+}
+
+void opndcoll_rfu_t::allocate_cu( 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 )
+ port = m_sfu_port;
+ else
+ port = m_alu_port;
+ if( !m_free_cu[port].empty() ) {
+ collector_unit_t *cu = m_free_cu[port].back();
+ m_free_cu[port].pop_back();
+ cu->allocate(id_oc_reg);
+ m_arbiter.add_read_requests(cu);
+ }
+ }
+}
+
+void opndcoll_rfu_t::allocate_reads()
+{
+ // process read requests that do not have conflicts
+ std::list<op_t> allocated = m_arbiter.allocate_reads();
+ std::map<unsigned,op_t> read_ops;
+ 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);
+ m_arbiter.allocate_for_read(bank,rr);
+ read_ops[bank] = rr;
+ }
+ std::map<unsigned,op_t>::iterator r;
+ for(r=read_ops.begin();r!=read_ops.end();++r ) {
+ op_t &op = r->second;
+ unsigned cu = op.get_oc_id();
+ unsigned operand = op.get_operand();
+ assert( cu < m_num_collectors );
+ m_cu[cu].collect_operand(operand);
+ }
+}
+
+
+void gpgpu_sim::decrement_atomic_count( unsigned sid, unsigned wid )
+{
+ m_sc[sid]->decrement_atomic_count(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);
+}
+
+void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *shader ) const
+{
+ if( m_free ) {
+ fprintf(fp," <free>\n");
+ } else {
+ shader->print_warp(m_warp,fp,0,0);
+ for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) {
+ if( m_not_ready.test(i) ) {
+ std::string r = m_src_op[i].get_reg_string();
+ fprintf(fp," '%s' not ready\n", r.c_str() );
+ }
+ }
+ }
+}
+
+void opndcoll_rfu_t::collector_unit_t::init( unsigned n,
+ inst_t **port,
+ unsigned num_banks,
+ unsigned log2_warp_size,
+ unsigned warp_size,
+ opndcoll_rfu_t *rfu )
+{
+ m_rfu=rfu;
+ m_cuid=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_bank_warp_shift=log2_warp_size;
+}
+
+void opndcoll_rfu_t::collector_unit_t::allocate( 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;
+ 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
+ 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);
+ }
+}
+
+void opndcoll_rfu_t::collector_unit_t::dispatch()
+{
+ assert( m_not_ready.none() );
+ m_rfu->shader_core()->move_warp(*m_port,m_warp);
+ m_free=true;
+ for( unsigned i=0; i<MAX_REG_OPERANDS;i++)
+ m_src_op[i].reset();
+}
+
+bool shader_core_ctx::ptx_thread_done( unsigned hw_thread_id ) const
+{
+ assert( hw_thread_id < m_config->n_thread_per_shader );
+ ptx_thread_info *thd = m_thread[ hw_thread_id ].m_functional_model_thread_state;
+ return (thd==NULL) || thd->is_done();
+}
+
+class ptx_thread_info *shader_core_ctx::get_thread_state( unsigned hw_thread_id )
+{
+ assert( hw_thread_id < m_config->n_thread_per_shader );
+ return m_thread[ hw_thread_id ].m_functional_model_thread_state;
+}
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 1e62995..44206af 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -72,6 +72,10 @@
#include <set>
#include <vector>
#include <list>
+#include <bitset>
+#include <utility>
+#include <algorithm>
+#include <deque>
#include "../cuda-sim/ptx.tab.h"
#include "../cuda-sim/dram_callback.h"
@@ -82,148 +86,238 @@
#include "dram.h"
#include "../abstract_hardware_model.h"
#include "scoreboard.h"
+#include "mem_fetch.h"
+#include "stats.h"
#ifndef SHADER_H
#define SHADER_H
#define NO_OP_FLAG 0xFF
-//READ_PACKET_SIZE: bytes: 6 address (flit can specify chanel so this gives up to ~2GB/channel, so good for now), 2 bytes [shaderid + mshrid](14 bits) + req_size(0-2 bits (if req_size variable) - so up to 2^14 = 16384 mshr total
+/* READ_PACKET_SIZE:
+ bytes: 6 address (flit can specify chanel so this gives up to ~2GB/channel, so good for now),
+ 2 bytes [shaderid + mshrid](14 bits) + req_size(0-2 bits if req_size variable) - so up to 2^14 = 16384 mshr total
+ */
+
#define READ_PACKET_SIZE 8
+
//WRITE_PACKET_SIZE: bytes: 6 address, 2 miscelaneous.
#define WRITE_PACKET_SIZE 8
-#include <bitset>
-const unsigned partial_write_mask_bits = 128; //must be at least size of largest memory access.
-typedef std::bitset<partial_write_mask_bits> partial_write_mask_t;
-
#define WRITE_MASK_SIZE 8
#define NO_PARTIAL_WRITE (partial_write_mask_t())
-//this is used a lot of places where it maybe should be more variable?
#define WORD_SIZE 4
//Set a hard limit of 32 CTAs per shader [cuda only has 8]
#define MAX_CTA_PER_SHADER 32
-typedef unsigned op_type;
-
-enum {
- NO_RECONVERGE = 0,
- POST_DOMINATOR = 1,
- MIMD = 2,
- DWF = 3,
- NUM_SIMD_MODEL
-};
-
-//Defines number of threads grouped together to be executed together
-
+class thread_ctx_t {
+public:
+ class ptx_thread_info *m_functional_model_thread_state;
+ unsigned m_cta_id; // hardware CTA this thread belongs
-typedef struct {
+ // 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
- address_type pc;
+ // per thread stats (ac stands for accumulative).
+ unsigned n_insn;
+ unsigned n_insn_ac;
+ unsigned n_l1_mis_ac;
+ unsigned n_l1_mrghit_ac;
+ unsigned n_l1_access_ac;
+};
- op_type op;
- memory_space_t space;
+class shd_warp_t {
+public:
+ shd_warp_t( class shader_core_ctx *shader, unsigned warp_size)
+ : m_shader(shader), m_warp_size(warp_size)
+ {
+ m_stores_outstanding=0;
+ m_inst_in_pipeline=0;
+ reset();
+ }
+ void reset()
+ {
+ assert( m_stores_outstanding==0);
+ assert( m_inst_in_pipeline==0);
+ 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;
+ m_last_fetch=0;
+ m_next=0;
+ for(unsigned i=0;i<IBUFFER_SIZE;i++)
+ m_ibuffer[i]=NULL;
+ }
+ void init( address_type start_pc, unsigned wid, unsigned active )
+ {
+ 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
+ }
- unsigned long long int memreqaddr;
- //Each instruction keeps track of which hardware thread it came from
- short hw_thread_id;
- short wlane;
+ bool done();
+ bool waiting();
- /* reg label of the instruction */
- unsigned out[4];
- unsigned in[4];
- unsigned char is_vectorin;
- unsigned char is_vectorout;
- int pred;
- int ar1, ar2;
- int arch_reg[MAX_REG_OPERANDS]; // register number for bank conflict evaluation
- unsigned data_size; // what is the size of the word being operated on?
- unsigned cycles; // number of cycles taken by current instruction
+ bool done_exit() const { return m_done_exit; }
+ void set_done_exit() { m_done_exit=true; }
- int reg_bank_access_pending;
- int reg_bank_conflict_stall_checked; // flag to turn off register bank conflict checker to avoid double stalling
+ void print( FILE *fout ) const;
+ void print_ibuffer( FILE *fout ) const;
- unsigned inst_type;
+ unsigned get_avail4fetch() const { return n_avail4fetch; }
+ void inc_avail4fetch() { n_avail4fetch++; }
+ void dec_avail4fetch() { n_avail4fetch--; }
- unsigned priority;
+ unsigned get_n_completed() const { return n_completed; }
+ void inc_n_completed() { n_completed++; }
- unsigned uid;
+ void set_last_fetch( unsigned long long sim_cycle ) { m_last_fetch=sim_cycle; }
- void *ptx_thd_info;
- dram_callback_t callback;
- unsigned warp_active_mask;
- unsigned long long ts_cycle;
- unsigned long long if_cycle;
- unsigned long long id_cycle;
- unsigned long long ex_cycle;
- unsigned long long mm_cycle;
+ unsigned get_n_atomic() const { return m_n_atomic; }
+ void inc_n_atomic() { m_n_atomic++; }
+ void dec_n_atomic() { m_n_atomic--; }
- bool cache_miss;
+ void inc_waiting_at_barrier() { n_waiting_at_barrier++; }
+ void clear_waiting_at_barrier() { n_waiting_at_barrier=0; }
-} inst_t;
+ 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; }
-typedef struct {
+ void ibuffer_fill( unsigned slot, const inst_t *pI )
+ {
+ assert(slot < IBUFFER_SIZE );
+ m_ibuffer[slot]=pI;
+ m_next=0;
+ }
+ bool ibuffer_empty() const
+ {
+ for( unsigned i=0; i < IBUFFER_SIZE; i++)
+ if(m_ibuffer[i])
+ return false;
+ return true;
+ }
+ void ibuffer_flush()
+ {
+ for(unsigned i=0;i<IBUFFER_SIZE;i++) {
+ if( m_ibuffer[i] )
+ dec_inst_in_pipeline();
+ m_ibuffer[i]=NULL;
+ }
+ }
+ const inst_t *ibuffer_next()
+ {
+ const inst_t *result = m_ibuffer[m_next];
+ return result;
+ }
+ void ibuffer_free()
+ {
+ m_ibuffer[m_next] = NULL;
+ }
+ void ibuffer_step()
+ {
+ m_next = (m_next+1)%IBUFFER_SIZE;
+ }
+ bool imiss_pending() const { return m_imiss_pending!=NULL; }
+ void set_imiss_pending( class mshr_entry *mshr )
+ {
+ m_imiss_pending=mshr;
+ }
+ void clear_imiss_pending() { m_imiss_pending=NULL; }
- class ptx_thread_info *ptx_thd_info; // pointer to the functional state of the thread in cuda-sim
+ bool stores_done() const { return m_stores_outstanding == 0; }
+ void inc_store_req() { m_stores_outstanding++; }
+ void dec_store_req()
+ {
+ assert( m_stores_outstanding > 0 );
+ m_stores_outstanding--;
+ }
- int avail4fetch; // 1 if its instrucion can be fetch into the pipeline, 0 otherwise
- int warp_priority;
+ bool inst_in_pipeline() const { return m_inst_in_pipeline > 0; }
- int id;
+ void inc_inst_in_pipeline() { m_inst_in_pipeline++; }
+ void dec_inst_in_pipeline()
+ {
+ assert( m_inst_in_pipeline > 0 );
+ m_inst_in_pipeline--;
+ }
- //unsigned n_completed; // number of threads in warp completed -- set for first thread in each warp
- //unsigned n_avail4fetch; // number of threads in warp available to fetch -- set for first thread in each warp
- //int n_waiting_at_barrier; // number of threads in warp that have reached the barrier
- unsigned in_scheduler; // used by dynamic warp formation for error check
+private:
+ static const unsigned IBUFFER_SIZE=2;
+ class shader_core_ctx *m_shader;
+ unsigned m_warp_id;
+ unsigned m_warp_size;
- int m_waiting_at_barrier;
- int m_reached_barrier;
+ 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
- unsigned n_insn;
- unsigned n_insn_ac;
- unsigned n_l1_mis_ac,
- n_l1_mrghit_ac,
- n_l1_access_ac; //used to collect "per thread" l1 miss statistics
- // ac stands for accumulative.
- unsigned cta_id; // which hardware CTA does this thread belong to?
-} thread_ctx_t;
+ class mshr_entry *m_imiss_pending;
+
+ const 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
-struct shd_warp_t
-{
- shd_warp_t(unsigned warp_size){reset(warp_size); assert(warp_size <= bitset_size);}
- void reset(unsigned warp_size){n_completed = warp_size; n_avail4fetch = n_waiting_at_barrier = 0; threads_completed.reset(); threads_functionally_executed.reset();}
+ bool m_done_exit; // true once thread exit has been registered for threads in this warp
- unsigned wid;
- unsigned n_completed; // number of threads in warp completed
- unsigned n_avail4fetch; // number of threads in warp available to fetch
- int n_waiting_at_barrier; // number of threads in warp that have reached the barrier
+ unsigned long long m_last_fetch;
- const static unsigned bitset_size = 32;
- std::bitset<bitset_size> threads_completed;
- std::bitset<bitset_size> threads_functionally_executed;
+ unsigned m_stores_outstanding; // number of store requests sent but not yet acknowledged
+ unsigned m_inst_in_pipeline;
};
inline unsigned hw_tid_from_wid(unsigned wid, unsigned warp_size, unsigned i){return wid * warp_size + i;};
inline unsigned wid_from_hw_tid(unsigned tid, unsigned warp_size){return tid/warp_size;};
-typedef struct {
-
- int m_stack_top;
+// bounded stack that implements pdom reconvergence (see MICRO'07 paper)
+class pdom_warp_ctx_t {
+public:
+ pdom_warp_ctx_t( unsigned wid, class shader_core_ctx *shdr );
- address_type *m_pc;
- unsigned int *m_active_mask;
- address_type *m_recvg_pc;
- unsigned int *m_calldepth;
+ void reset();
+ void launch( address_type start_pc, unsigned active_mask );
+ void pdom_update_warp_mask();
- unsigned long long *m_branch_div_cycle;
+ unsigned get_active_mask() const;
+ void get_pdom_stack_top_info( unsigned *pc, unsigned *rpc );
+ unsigned get_rp() const;
+ void print(FILE*fp) const;
-} pdom_warp_ctx_t; // bounded stack that implements pdom reconvergence (see MICRO'07 paper)
+private:
+ unsigned m_warp_id;
+ class shader_core_ctx *m_shader;
+ unsigned m_stack_top;
+ unsigned m_warp_size;
+
+ address_type *m_pc;
+ unsigned int *m_active_mask;
+ address_type *m_recvg_pc;
+ unsigned int *m_calldepth;
+
+ unsigned long long *m_branch_div_cycle;
+};
enum mshr_status {
INITIALIZED = 0,
+ INVALID,
IN_ICNT2MEM,
IN_CBTOL2QUEUE,
IN_L2TODRAMQUEUE,
@@ -257,78 +351,113 @@ enum mem_req_stat {
NUM_MEM_REQ_STAT
};
#include <vector>
-typedef struct mshr_entry_t {
-#ifdef _GLIBCXX_DEBUG
- //satisfy cxx debug conditions on iterators, needs to be nonsingular to copy, which messes completely with structures containing them.
- mshr_entry_t(){
- static std::vector<mshr_entry_t> dummy_vector;
- this_mshr = dummy_vector.begin(); //initialize it to something nonsingular so it can be copied.
- }
-#endif
-private:
- friend class mshr_shader_unit;
- std::vector<mshr_entry_t>::iterator this_mshr; //to ease tracking and update.
-public:
- unsigned request_uid;
-
- /* memory address of the data */
- unsigned long long int addr;
-
- // instructions are stored here.
- std::vector<inst_t> insts;
-
- /* Current stage of the load: fetched or not? */
- bool fetched(){return status == FETCHED;};
-
- bool iswrite;
-
- bool merged_on_other_reqest; //true if waiting for another mshr - this mshr doesn't send a memory request
- struct mshr_entry_t *merged_requests; //mshrs waiting on this mshr
- enum mshr_status status;
-
- void *mf; // link to corresponding memory fetch structure
-
- //unsigned space; //does below.
- bool istexture; //if it's a request from the texture cache
- bool isconst; //if it's a request from the constant cache
- bool islocal; //if it's a request to the local memory of a thread
+class mshr_entry {
+public:
+ mshr_entry()
+ {
+ m_status = INVALID;
+ m_merged_requests=NULL;
+ m_mf=NULL;
+ m_id=0;
+ }
+ void set_id( unsigned n ) { m_id = n; }
+ 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 set_status( enum mshr_status status );
+ void merge( mshr_entry *mshr )
+ {
+ //merge this request;
+ m_merged_requests = mshr;
+ mshr->m_merged_on_other_reqest = true;
+ }
- bool wt_no_w2cache; //in write_through, sometimes need to prevent writing back returning data into cache, because its been written in the meantime.
-} mshr_entry;
+ dram_callback_t &get_atomic_callback()
+ {
+ assert(isatomic());
+ return m_insts[0].callback;
+ }
+ mshr_entry *get_last_merged()
+ {
+ assert(m_status!=INVALID);
+ mshr_entry *mshr_hit = this;
+ while (mshr_hit->m_merged_requests)
+ mshr_hit = mshr_hit->m_merged_requests;
+ return mshr_hit;
+ }
+ void get_insts( std::vector<inst_t> &done_insts )
+ {
+ done_insts.insert(done_insts.end(),m_insts.begin(),m_insts.end());
+ }
+ void add_to_queue( std::deque<mshr_entry*> &q )
+ {
+ // place all merged requests in return queue
+ mshr_entry *req = this;
+ while (req) {
+ q.push_back(req);
+ req = req->m_merged_requests;
+ }
+ }
-enum mem_access_type {
- GLOBAL_ACC_R = 0,
- LOCAL_ACC_R = 1,
- CONST_ACC_R = 2,
- TEXTURE_ACC_R = 3,
- GLOBAL_ACC_W = 4,
- LOCAL_ACC_W = 5,
- L2_WRBK_ACC = 6,
- NUM_MEM_ACCESS_TYPE = 7
+ unsigned get_warp_id() const { return m_warp_id; }
+ bool ismerged() const { return m_merged_on_other_reqest; }
+ bool fetched() const { return m_status == FETCHED;};
+ bool iswrite() const { return m_iswrite; }
+ bool isinst() const { return m_isinst; }
+ bool istexture() const { return m_istexture; }
+ bool isconst() const { return m_isconst; }
+ bool islocal() const { return m_islocal; }
+ bool has_inst() const { return m_insts.size()>0; }
+ unsigned num_inst() const { return m_insts.size(); }
+ inst_t &get_inst(unsigned n)
+ {
+ 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);
+ }
+ new_addr_type get_addr() const { return m_addr; }
+ void print(FILE *fp, unsigned mask) const;
+
+private:
+ unsigned m_id;
+ unsigned m_request_uid;
+ unsigned m_warp_id;
+ new_addr_type m_addr; // address being fetched
+ std::vector<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
+ enum mshr_status m_status;
+ class mem_fetch *m_mf; // link to corresponding memory fetch structure
+ bool m_isinst; //if it's a request from the instruction cache
+ bool m_istexture; //if it's a request from the texture cache
+ bool m_isconst; //if it's a request from the constant cache
+ bool m_islocal; //if it's a request to the local memory of a thread
+ bool m_wt_no_w2cache; //in write_through, sometimes need to prevent writing back returning data into cache, because its been written in the meantime.
};
-
-/* A pointer to the function that glues the shader with the memory hiearchy */
-typedef unsigned char (*fq_push_t)(unsigned long long int addr, int bsize, unsigned char readwrite,
- partial_write_mask_t,
- int sid, int wid, mshr_entry* mshr, int cache_hits_waiting,
- enum mem_access_type mem_acc, address_type pc);
-
-typedef unsigned char (*fq_has_buffer_t)(unsigned long long int addr, int bsize, bool write, int sid);
-
const unsigned WARP_PER_CTA_MAX = 32;
typedef std::bitset<WARP_PER_CTA_MAX> warp_set_t;
-inst_t *first_valid_thread( inst_t *warp );
-void move_warp( inst_t *dst, inst_t *src );
-bool pipeline_regster_empty( inst_t *reg );
-std::list<unsigned> get_regs_written( inst_t *warp );
-int register_bank(int regnum, int tid);
+int register_bank(int regnum, int tid, unsigned num_banks, unsigned bank_warp_shift);
+
class shader_core_ctx;
-void shader_print_warp( const shader_core_ctx *shader, inst_t *warp, FILE *fout, int stage_width, int print_mem, int mask ) ;
-class opndcoll_rfu_t{ // operand collector based register file unit
+class opndcoll_rfu_t { // operand collector based register file unit
public:
// constructors
opndcoll_rfu_t()
@@ -343,29 +472,28 @@ public:
void init( unsigned num_collectors_alu,
unsigned num_collectors_sfu,
unsigned num_banks,
- const shader_core_ctx *shader );
+ shader_core_ctx *shader,
+ inst_t **alu_port,
+ inst_t **sfu_port );
// modifiers
- void writeback( inst_t *warp )
+ bool writeback( const inst_t &fvt );
+ bool writeback( inst_t *warp ); // might cause stall
+
+ void step( inst_t *&id_oc_reg )
{
- // prefer not to stall writeback
- inst_t *fvt=first_valid_thread(warp);
- if (!fvt) return;
- unsigned tid = fvt->hw_thread_id;
- std::list<unsigned> regs = get_regs_written(fvt);
- std::list<unsigned>::iterator r;
- for( r=regs.begin(); r!=regs.end();r++ ) {
- unsigned reg = *r;
- unsigned bank = register_bank(reg,tid);
- m_arbiter.allocate_bank_for_write(bank,op_t(fvt,reg));
- }
+ dispatch_ready_cu();
+ allocate_reads();
+ allocate_cu(id_oc_reg);
+ process_banks();
}
- void step( inst_t *id_oc_reg )
+ void step( inst_t *&alu_issue_port, inst_t *&sfu_issue_port )
{
dispatch_ready_cu();
allocate_reads();
- allocate_cu(id_oc_reg);
+ allocate_cu(alu_issue_port);
+ allocate_cu(sfu_issue_port);
process_banks();
}
@@ -374,12 +502,14 @@ public:
fprintf(fp,"\n");
fprintf(fp,"Operand Collector State:\n");
for( unsigned n=0; n < m_num_collectors; n++ ) {
- fprintf(fp," CU-%u: ", n);
+ fprintf(fp," CU-%2u: ", n);
m_cu[n].dump(fp,m_shader);
}
m_arbiter.dump(fp);
}
+ shader_core_ctx *shader_core() { return m_shader; }
+
private:
void process_banks()
@@ -387,61 +517,9 @@ private:
m_arbiter.reset_alloction();
}
- void 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( !pipeline_regster_empty(port) )
- continue;
- dispatch_unit_t &du = p->second;
- collector_unit_t *cu = du.find_ready();
- if( cu ) {
- cu->dispatch();
- m_free_cu[port].push_back(cu);
- }
- }
- }
-
- void allocate_cu( inst_t *id_oc_reg )
- {
- inst_t *fvi = first_valid_thread(id_oc_reg);
- if( fvi ) {
- inst_t *port = NULL;
- if( fvi->op == SFU_OP )
- port = m_sfu_port;
- else
- port = m_alu_port;
- if( !m_free_cu[port].empty() ) {
- collector_unit_t *cu = m_free_cu[port].back();
- m_free_cu[port].pop_back();
- cu->allocate(id_oc_reg);
- m_arbiter.add_read_requests(cu);
- }
- }
- }
-
- void allocate_reads()
- {
- // process read requests that do not have conflicts
- std::list<op_t> allocated = m_arbiter.allocate_reads();
- std::map<unsigned,op_t> read_ops;
- 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_arbiter.allocate_for_read(bank,rr);
- read_ops[bank] = rr;
- }
- std::map<unsigned,op_t>::iterator r;
- for(r=read_ops.begin();r!=read_ops.end();++r ) {
- op_t &op = r->second;
- unsigned cu = op.get_oc_id();
- unsigned operand = op.get_operand();
- m_cu[cu].collect_operand(operand);
- }
- }
+ void dispatch_ready_cu();
+ void allocate_cu( inst_t *&id_oc_reg );
+ void allocate_reads();
// types
@@ -451,7 +529,7 @@ private:
public:
op_t() { m_valid = false; }
- op_t( collector_unit_t *cu, unsigned op, unsigned reg )
+ op_t( collector_unit_t *cu, unsigned op, unsigned reg, unsigned num_banks, unsigned bank_warp_shift )
{
m_valid = true;
m_fvi=NULL;
@@ -459,16 +537,17 @@ private:
m_operand = op;
m_register = reg;
m_tid = cu->get_tid();
- m_bank = register_bank(reg,m_tid);
+ m_bank = register_bank(reg,m_tid,num_banks,bank_warp_shift);
}
- op_t( inst_t *fvi, unsigned reg )
+ op_t( const inst_t *fvi, unsigned reg, unsigned num_banks, unsigned bank_warp_shift )
{
+ m_valid=true;
m_fvi=fvi;
m_register=reg;
m_cu=NULL;
m_operand = -1;
m_tid = fvi->hw_thread_id;
- m_bank = register_bank(reg,m_tid);
+ m_bank = register_bank(reg,m_tid,num_banks,bank_warp_shift);
}
// accessors
@@ -487,7 +566,7 @@ private:
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, w:%02u> ", m_register,m_tid/::warp_size);
+ fprintf(fp," <R%u, fvi tid:%02u> ", m_register,m_fvi->hw_thread_id );
}
std::string get_reg_string() const
{
@@ -501,7 +580,7 @@ private:
private:
bool m_valid;
collector_unit_t *m_cu;
- inst_t *m_fvi;
+ const inst_t *m_fvi;
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;
@@ -591,12 +670,18 @@ private:
}
}
}
+ bool bank_idle( unsigned bank ) const
+ {
+ return m_allocated_bank[bank].is_free();
+ }
void allocate_bank_for_write( unsigned bank, const op_t &op )
{
+ assert( bank < m_num_banks );
m_allocated_bank[bank].alloc_write(op);
}
void allocate_for_read( unsigned bank, const op_t &op )
{
+ assert( bank < m_num_banks );
m_allocated_bank[bank].alloc_read(op);
}
void reset_alloction()
@@ -622,83 +707,51 @@ private:
collector_unit_t()
{
m_free = true;
- m_warp = (inst_t*)calloc(sizeof(inst_t),::warp_size);
+ 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;
}
// accessors
- bool ready() const
- {
- return (!m_free) && m_not_ready.none() && pipeline_regster_empty(m_port);
- }
+ bool ready() const;
const op_t *get_operands() const { return m_src_op; }
- void dump(FILE *fp, const shader_core_ctx *shader ) const
- {
- if( m_free ) {
- fprintf(fp," <free>\n");
- } else {
- shader_print_warp(shader,m_warp,fp,::warp_size,0,0);
- for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) {
- if( m_not_ready.test(i) ) {
- std::string r = m_src_op[i].get_reg_string();
- fprintf(fp," '%s' not ready\n", r.c_str() );
- }
- }
- }
- }
+ 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) { m_cuid=n; m_port=port; }
- void allocate( inst_t *pipeline_reg )
- {
- assert(m_free);
- assert(m_not_ready.none());
- m_free = false;
- inst_t *fvi = first_valid_thread(pipeline_reg);
- if( fvi ) {
- m_tid = fvi->hw_thread_id;
- m_warp_id = m_tid/::warp_size;
- 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
- if( reg_num >= 0 ) { // valid register
- m_src_op[op] = op_t( this, op, reg_num );
- m_not_ready.set(op);
- } else
- m_src_op[op] = op_t();
- }
- move_warp(m_warp,pipeline_reg);
- }
- }
+ void init(unsigned n,
+ inst_t **port,
+ unsigned num_banks,
+ unsigned log2_warp_size,
+ unsigned warp_size,
+ opndcoll_rfu_t *rfu );
+ void allocate( inst_t *&pipeline_reg );
void collect_operand( unsigned op )
{
m_not_ready.reset(op);
}
- void dispatch()
- {
- assert( m_not_ready.none() );
- move_warp(m_port,m_warp);
- m_free=true;
- for( unsigned i=0; i<MAX_REG_OPERANDS;i++)
- m_src_op[i].reset();
- }
+ void dispatch();
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
+ inst_t **m_port; // pipeline register to issue to when ready
unsigned m_warp_id;
inst_t *m_warp;
op_t *m_src_op;
std::bitset<MAX_REG_OPERANDS> m_not_ready;
+ unsigned m_num_banks;
+ unsigned m_bank_warp_shift;
+ opndcoll_rfu_t *m_rfu;
};
class dispatch_unit_t {
@@ -748,16 +801,18 @@ private:
unsigned m_num_collectors;
unsigned m_num_banks;
+ unsigned m_bank_warp_shift;
+ unsigned m_warp_size;
collector_unit_t *m_cu;
arbiter_t m_arbiter;
- inst_t *m_alu_port;
- inst_t *m_sfu_port;
+ inst_t **m_alu_port;
+ inst_t **m_sfu_port;
- typedef std::map<inst_t*/*port*/,dispatch_unit_t> port_to_du_t;
+ typedef std::map<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;
- const shader_core_ctx *m_shader;
+ std::map<inst_t**,std::list<collector_unit_t*> > m_free_cu;
+ shader_core_ctx *m_shader;
};
class barrier_set_t {
@@ -782,7 +837,7 @@ public:
void warp_exit( unsigned warp_id );
// assertions
- bool warp_waiting_at_barrier( unsigned warp_id );
+ bool warp_waiting_at_barrier( unsigned warp_id ) const;
// debug
void dump() const;
@@ -796,213 +851,431 @@ private:
warp_set_t m_warp_at_barrier;
};
-class mshr_shader_unit;
class warp_tracker;
class warp_tracker_pool;
+enum memory_pipe_t {
+ NO_MEM_PATH = 0,
+ SHARED_MEM_PATH,
+ GLOBAL_MEM_PATH,
+ TEXTURE_MEM_PATH,
+ CONSTANT_MEM_PATH,
+ NUM_MEM_PATHS //not a mem path
+};
+
+class mem_access_t {
+public:
+ mem_access_t() : space(undefined_space)
+ {
+ init();
+ }
+ mem_access_t(address_type a, memory_space_t s, memory_pipe_t p, bool atomic, bool w, unsigned r, unsigned quarter, unsigned idx )
+ {
+ init();
+ addr = a;
+ space = s;
+ mem_pipe = p;
+ isatomic = atomic;
+ iswrite = w;
+ req_size = r;
+ quarter_count[quarter]++;
+ warp_indices.push_back(idx);
+ }
+
+ bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse
+
+private:
+ void init()
+ {
+ uid=++next_access_uid;
+ addr=0;
+ req_size=0;
+ order=0;
+ _quarter_count_all=0;
+ mem_pipe = NO_MEM_PATH;
+ isatomic = false;
+ cache_hit = false;
+ cache_checked = false;
+ recheck_cache = false;
+ iswrite = false;
+ need_wb = false;
+ wb_addr = 0;
+ reserved_mshr = NULL;
+ }
+
+public:
+
+ unsigned uid;
+ address_type addr; //address of the segment to load.
+ unsigned req_size; //bytes
+ unsigned order; // order of accesses, based on banks.
+ union{
+ unsigned _quarter_count_all;
+ char quarter_count[4]; //access counts to each quarter of segment, for compaction;
+ };
+ std::vector<unsigned> warp_indices; // warp indicies for this request.
+ memory_space_t space;
+ memory_pipe_t mem_pipe;
+ bool isatomic;
+ bool cache_hit;
+ bool cache_checked;
+ bool recheck_cache;
+ bool iswrite;
+ bool need_wb;
+ address_type wb_addr; // writeback address (if necessary).
+ mshr_entry* reserved_mshr;
+
+private:
+ static unsigned next_access_uid;
+};
+
+class mshr_lookup {
+public:
+ mshr_lookup( const struct shader_core_config *config ) { m_shader_config = config; }
+ bool can_merge(mshr_entry * mshr);
+ void mshr_fast_lookup_insert(mshr_entry* mshr);
+ void mshr_fast_lookup_remove(mshr_entry* mshr);
+ mshr_entry* shader_get_mergeable_mshr(mshr_entry* mshr);
+
+private:
+ void insert(mshr_entry* mshr);
+ mshr_entry* lookup(new_addr_type addr) const;
+ void remove(mshr_entry* mshr);
+
+ typedef std::multimap<new_addr_type, mshr_entry*> mshr_lut_t; // multimap since multiple mshr entries can have the same tag
+
+ const shader_core_config *m_shader_config;
+ mshr_lut_t m_lut;
+};
+
+class mshr_shader_unit {
+public:
+ mshr_shader_unit( const shader_core_config *config );
+
+ bool has_mshr(unsigned num)
+ {
+ return (num <= m_free_list.size());
+ }
+
+ //return queue access; (includes texture pipeline return)
+ mshr_entry* return_head();
+
+ //return queue pop; (includes texture pipeline return)
+ void pop_return_head();
+
+ mshr_entry* add_mshr(mem_access_t &access, 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);
+
+private:
+ mshr_entry *alloc_free_mshr(bool istexture);
+ void free_mshr( mshr_entry *mshr );
+ unsigned mshr_used() const;
+ bool has_return()
+ {
+ return (not m_mshr_return_queue.empty()) or
+ ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched());
+ }
+ std::deque<mshr_entry*> &choose_return_queue();
+
+ const struct shader_core_config *m_shader_config;
+
+ typedef std::vector<mshr_entry> mshr_storage_type;
+ mshr_storage_type m_mshrs;
+ std::deque<mshr_entry*> m_free_list;
+ std::deque<mshr_entry*> m_mshr_return_queue;
+ std::deque<mshr_entry*> m_texture_mshr_pipeline;
+ unsigned m_max_mshr_used;
+ mshr_lookup m_mshr_lookup;
+};
+
+struct shader_queues_t {
+ std::vector<mem_access_t> shared;
+ std::vector<mem_access_t> constant;
+ std::vector<mem_access_t> texture;
+ std::vector<mem_access_t> local_global;
+};
+
+struct insn_latency_info {
+ unsigned pc;
+ unsigned long latency;
+};
+
+struct ifetch_buffer_t {
+ ifetch_buffer_t() { m_valid=false; }
+
+ ifetch_buffer_t( address_type pc, unsigned nbytes, unsigned warp_id )
+ {
+ m_valid=true;
+ m_pc=pc;
+ m_nbytes=nbytes;
+ m_warp_id=warp_id;
+ }
+
+ bool m_valid;
+ address_type m_pc;
+ unsigned m_nbytes;
+ unsigned m_warp_id;
+};
+
+// Struct for storing warp information in fixeddelay_queue
+struct fixeddelay_queue_warp_t {
+ unsigned long long ready_cycle;
+ std::vector<int> tids; // list of tid's in this warp (to unlock)
+ inst_t inst;
+};
+
+struct fixeddelay_queue_warp_comp {
+ inline bool operator()(const fixeddelay_queue_warp_t& left,const fixeddelay_queue_warp_t& right) const
+ {
+ return left.ready_cycle < right.ready_cycle;
+ }
+};
+
+typedef address_type (*tag_func_t)(address_type add, unsigned line_size);
+
class shader_core_ctx : public core_t
{
public:
- shader_core_ctx( const char *name, int sid,
- unsigned int n_threads,
- unsigned int n_mshr,
- fq_push_t fq_push,
- fq_has_buffer_t fq_has_buffer,
- unsigned model,
- unsigned max_warps_per_cta, unsigned max_cta_per_core );
+ shader_core_ctx( class gpgpu_sim *gpu,
+ const char *name,
+ unsigned shader_id,
+ unsigned tpc_id,
+ const struct shader_core_config *config,
+ struct shader_core_stats *stats );
+
+ void issue_block2core( class kernel_info_t &kernel );
+ void get_pdom_stack_top_info( unsigned tid, unsigned *pc, unsigned *rpc );
+ void new_cache_window();
+ bool ptx_thread_done( unsigned hw_thread_id ) const;
+ class ptx_thread_info *get_thread_state( unsigned hw_thread_id );
- virtual void set_at_barrier( unsigned cta_id, unsigned warp_id );
+ virtual void set_at_barrier( unsigned cta_id, unsigned warp_id );
virtual void warp_exit( unsigned warp_id );
- virtual bool warp_waiting_at_barrier( unsigned warp_id );
+ virtual bool warp_waiting_at_barrier( unsigned warp_id ) const;
+ virtual bool warp_waiting_for_atomics( unsigned warp_id ) const;
+ virtual class gpgpu_sim *get_gpu();
+ void set_at_memory_barrier( unsigned warp_id );
+ bool warp_waiting_at_mem_barrier( unsigned warp_id );
void allocate_barrier( unsigned cta_id, warp_set_t warps );
void deallocate_barrier( unsigned cta_id );
+ void decrement_atomic_count( unsigned wid );
-////
-
- const char *name;
- int sid;
+ void cycle();
+ void cycle_gt200();
- // array of the threads running on this shader core
- thread_ctx_t *thread;
- unsigned int n_threads;
- unsigned int last_issued_thread;
+ void reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed );
+ void init_warps(unsigned start_thread, unsigned end_thread);
- //per warp information array
- std::vector<shd_warp_t> warp;
+ unsigned max_cta( class function_info *kernel );
+ void cache_flush();
+ void display_pdom_state(FILE *fout, int mask );
+ void display_pipeline( FILE *fout, int print_mem, int mask3bit );
+ void register_cta_thread_exit(int cta_num );
+ void fill_shd_L1_with_new_line( class mem_fetch * mf );
+ 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 );
+ 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);
+ 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; }
+ unsigned get_n_diverge() const { return m_n_diverge; }
+ unsigned get_thread_n_insn( unsigned tid ) const { return m_thread[tid].n_insn; }
+ unsigned get_thread_n_insn_ac( unsigned tid ) const { return m_thread[tid].n_insn_ac; }
+ unsigned get_thread_n_l1_mis_ac( unsigned tid ) const { return m_thread[tid].n_l1_mis_ac; }
+ unsigned get_thread_n_l1_mrghit_ac( unsigned tid ) const { return m_thread[tid].n_l1_mrghit_ac; }
+ unsigned get_thread_n_l1_access_ac( unsigned tid ) const { return m_thread[tid].n_l1_access_ac; }
+ unsigned get_max_mshr_used() const { return m_mshr_unit->get_max_mshr_used(); }
+ void L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const;
+ void L1texcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const;
+ void L1constcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const;
+ unsigned get_n_active_cta() const { return m_n_active_cta; }
+ float L1_windowed_cache_miss_rate( int x ) const { return shd_cache_windowed_cache_miss_rate(m_L1D,x); }
+ float L1tex_windowed_cache_miss_rate( int x ) const { return shd_cache_windowed_cache_miss_rate(m_L1T,x); }
+ float L1const_windowed_cache_miss_rate( int x ) const { return shd_cache_windowed_cache_miss_rate(m_L1C,x); }
+
+private:
- barrier_set_t m_barriers;
+ void clear_stage_reg(int stage);
- //Keeps track of which warp of instructions to fetch/execute
- int next_warp;
+ address_type next_pc( int tid ) const;
- // number of threads to be completed ( ==0 when all thread on this core completed)
- int not_completed;
- // number of Cuda Thread Arrays (blocks) currently running on this shader.
- int n_active_cta;
- //Keep track of multiple CTAs in shader
- int cta_status[MAX_CTA_PER_SHADER];
- // registers holding the instruction between pipeline stages.
- // see below for definition of pipeline stages
- inst_t** pipeline_reg;
- inst_t** pre_mem_pipeline;
- opndcoll_rfu_t m_opndcoll_new;
- int warp_part2issue; // which part of warp to issue to pipeline
- int new_warp_TS; // new warp at TS pipeline register
+ void ptx_exec_inst( inst_t &inst );
+ void fetch_new();
+ void issue_warp(const inst_t *pI, unsigned active_mask, inst_t *&warp, unsigned warp_id );
+ void decode_new();
- shd_cache_t *L1cache;
- shd_cache_t *L1texcache;
- shd_cache_t *L1constcache;
+ void fetch();
- // pointer to memory access wrapping function
- fq_push_t fq_push;
- fq_has_buffer_t fq_has_buffer;
+ 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);
- // simulation cycles happened to the shader, kept for cacheline replacement
- unsigned int gpu_cycle;
- // number of instructions committed by this shader core
- unsigned int num_sim_insn;
+ void decode();
- // reconvergence
- unsigned int model;
+ void preexecute();
- // Structure is used to keep track of the branching within the warp of instructions.
- // As a group of instructions is grouped together from different threads to be executed, when
- // a branch does occur, then the sub-set that does not get run will be given the value of warp_priority,
- // and warp_priority will increase. Each time a sub-set branches further, a similar scheme is used.
- // When a sub-set completes fully, then this table will determine which next sub-set to finish, which
- // will be the next largest value in the table.
- int branch_priority;
- int* max_branch_priority; //Keeps track of the maximum priority of the threads running within a warp. need n_threads number of these
+ void execute();
+ void execute_pipe( unsigned pipeline, unsigned next_stage );
- // pdom reconvergence context for each warp
- pdom_warp_ctx_t *pdom_warp;
+ void pre_memory();
- int waiting_at_barrier; // number of threads current waiting at a barrier in this shader.
- int RR_k; //counter for register read pipeline
+ void memory(); // advance memory pipeline stage
+ void memory_queue();
+ void memory_shared_process_warp();
+ void memory_const_process_warp();
+ void memory_texture_process_warp();
+ void memory_global_process_warp();
+ bool memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool memory_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ address_type translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader );
- int using_dwf; //is the scheduler using dynamic warp formation
- int using_rrstage; //is the pipeline using an extra stage for register read
- int using_commit_queue; //is the scheduler using commit_queue?
+ mem_stage_stall_type ccache_check(mem_access_t& access){ return NO_RC_FAIL;}
+ mem_stage_stall_type tcache_check(mem_access_t& access){ return NO_RC_FAIL;}
+ mem_stage_stall_type dcache_check(mem_access_t& access);
- delay_queue *thd_commit_queue;
+ typedef mem_stage_stall_type (shader_core_ctx::*cache_check_t)(mem_access_t&);
- int pending_shmem_bkacc; // 0 = check conflict for new insn
- int pending_cache_bkacc; // 0 = check conflict for new insn
+ mem_stage_stall_type process_memory_access_queue( shader_core_ctx::cache_check_t cache_check,
+ unsigned ports_per_bank,
+ unsigned memory_send_max,
+ std::vector<mem_access_t> &accessq );
- bool shader_memory_new_instruction_processed;
+ typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size);
+
+ int null_bank_func(address_type add, unsigned line_size);
+ int shmem_bank_func(address_type add, unsigned line_size);
+ int dcache_bank_func(address_type add, unsigned line_size);
- int pending_mem_access; // number of memory access to be serviced (use for W0 classification)
+ void get_memory_access_list( bank_func_t bank_func,
+ tag_func_t tag_func,
+ memory_pipe_t mem_pipe,
+ unsigned warp_parts,
+ unsigned line_size,
+ bool limit_broadcast,
+ std::vector<mem_access_t> &accessq );
+ mem_stage_stall_type send_mem_request(mem_access_t &access);
- int pending_cmem_acc; //number of accesses to differrnt addresses in the constant memory cache
+ void check_stage_pcs( unsigned stage );
+ void check_pm_stage_pcs( unsigned stage );
- unsigned int n_diverge; // number of divergence occurred in this shader
+ 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);
- //Shader core resources
- unsigned int shmem_size;
- unsigned int n_registers; //registers available in the shader core
- unsigned int n_cta; //Limit on number of concurrent CTAs in shader core
+ unsigned char fq_push( unsigned long long int addr,
+ int bsize,
+ unsigned char write,
+ partial_write_mask_t partial_write_mask,
+ int wid, mshr_entry* mshr,
+ int cache_hits_waiting,
+ enum mem_access_type mem_acc,
+ address_type pc );
- mshr_shader_unit *mshr_unit;
+ 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 );
- //
- // Fixed-delay queue for locked warps
- //
+ 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 );
- // Struct for storing warp information in fixeddelay_queue
- struct fixeddelay_queue_warp_t {
- int grid_num;
- unsigned long long ready_cycle;
- std::vector<int> tids; // list of tid's in this warp (to unlock)
- };
- struct fixeddelay_queue_warp_comp {
- inline bool operator()(const fixeddelay_queue_warp_t& left,const fixeddelay_queue_warp_t& right) const
- {
- return left.ready_cycle < right.ready_cycle;
- }
- };
+ // general information
+ unsigned m_sid; // shader id
+ unsigned m_tpc; // texture processor cluster id (aka, node id when using interconnect concentration)
+ const char *m_name;
+ const shader_core_config *m_config;
+ class gpgpu_sim *m_gpu;
- // The queue
- std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp> fixeddelay_queue;
+ // statistics
+ struct shader_core_stats *m_stats; // pointer to single object shared by all shader cores in GPU
+ unsigned int m_num_sim_insn; // number of instructions committed by this shader core
+ unsigned int m_n_diverge; // number of divergence occurred in this shader
- // Scoreboard
- Scoreboard *scrb;
-};
+ // CTA scheduling / hardware thread allocation
+ int m_n_active_cta; // number of Cooperative Thread Arrays (blocks) currently running on this shader.
+ int m_cta_status[MAX_CTA_PER_SHADER]; // CTAs status
+ int m_not_completed; // number of threads to be completed (==0 when all thread on this core completed)
-typedef shader_core_ctx shader_core_ctx_t;
+ // thread contexts
+ thread_ctx_t *m_thread; // functional state, per thread fetch state
+ std::vector<shd_warp_t> m_warp; // per warp information array
+ barrier_set_t m_barriers;
+ ifetch_buffer_t m_inst_fetch_buffer;
+ pdom_warp_ctx_t **m_pdom_warp; // pdom reconvergence context for each warp
-typedef struct {
- unsigned pc;
- unsigned long latency;
- void *ptx_thd_info;
-} insn_latency_info;
+ class warp_tracker_pool *m_warp_tracker;
+ inst_t** m_pipeline_reg;
+ inst_t** pre_mem_pipeline;
+ Scoreboard *m_scoreboard;
+ opndcoll_rfu_t m_operand_collector;
+ mshr_shader_unit *m_mshr_unit;
+ shader_queues_t m_memory_queue;
+ fifo_pipeline<std::vector<int> > *m_thd_commit_queue;
+ std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp> m_fixeddelay_queue;
+ // fetch
+ int m_last_warp_fetched;
+ int m_last_warp_issued;
-shader_core_ctx_t* shader_create( const char *name, int sid, unsigned int n_threads,
- unsigned int n_mshr, fq_push_t fq_push, fq_has_buffer_t fq_has_buffer, unsigned int model);
-unsigned shader_reinit(shader_core_ctx_t *sc, int start_thread, int end_thread);
-void shader_init_CTA(shader_core_ctx_t *shader, int start_thread, int end_thread);
+ 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
-void shader_fetch( shader_core_ctx_t *shader,
- unsigned int shader_number,
- int grid_num );
-void shader_decode( shader_core_ctx_t *shader,
- unsigned int shader_number,
- unsigned int grid_num );
-void shader_preexecute( shader_core_ctx_t *shader,
- unsigned int shader_number );
-void shader_execute( shader_core_ctx_t *shader,
- unsigned int shader_number );
-void shader_pre_memory( shader_core_ctx_t *shader,
- unsigned int shader_number );
-void shader_const_memory( shader_core_ctx_t *shader,
- unsigned int shader_number );
-void shader_texture_memory( shader_core_ctx_t *shader,
- unsigned int shader_number );
-void shader_memory( shader_core_ctx_t *shader,
- unsigned int shader_number );
-void shader_writeback( shader_core_ctx_t *shader,
- unsigned int shader_number,
- int grid_num );
+ int *m_ready_warps;
+ int *m_tmp_ready_warps;
+ int *m_fetch_tid_out;
-bool shader_warp_scoreboard_hazard(shader_core_ctx_t *shader, int warp_id);
-void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id);
+ // pre-execute stage
+ int m_dwf_RR_k; // counter for register read pipeline
+ int *m_dwf_rrstage_bank_access_counter;
-void shader_display_pipeline(shader_core_ctx_t *shader, FILE *fout, int print_mem, int mask3bit );
-void shader_dump_thread_state(shader_core_ctx_t *shader, FILE *fout );
-void shader_cycle( shader_core_ctx_t *shader,
- unsigned int shader_number,
- int grid_num );
+ shd_cache_t *m_L1I; // instruction cache
+ shd_cache_t *m_L1D; // data cache (global/local memory accesses)
+ shd_cache_t *m_L1T; // texture cache
+ shd_cache_t *m_L1C; // constant cache
-void mshr_print(FILE *fp, shader_core_ctx_t *shader);
+ bool m_shader_memory_new_instruction_processed;
+ int m_pending_mem_access; // number of memory access to be serviced (use for W0 classification)
-void mshr_update_status(mshr_entry* mshr, enum mshr_status new_status);
+ // used in writeback
+ int *m_pl_tid;
+ insn_latency_info *m_mshr_lat_info;
+ insn_latency_info *m_pl_lat_info;
-mshr_entry* fetchMSHR(delay_queue** mshr, shader_core_ctx_t* sc);
-mshr_entry* shader_check_mshr4tag(shader_core_ctx_t* sc, unsigned long long int addr,int mem_type);
-void shader_update_mshr(shader_core_ctx_t* sc, unsigned long long int fetched_addr, unsigned int mshr_idx, int mem_type );
-void shader_visualizer_dump(FILE *fp, shader_core_ctx_t* sc);
+ class thread_pc_tracker *m_thread_pc_tracker;
+};
void init_mshr_pool();
mshr_entry* alloc_mshr_entry();
void free_mshr_entry( mshr_entry * );
-void shader_clean(shader_core_ctx_t *sc, unsigned int n_threads);
-void shader_cache_flush(shader_core_ctx_t* sc);
-
-void shader_call_thread_done( shader_core_ctx_t *shader, int grid_num, inst_t &done_inst );
-void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_space_t space, int grid_num);
-void shader_process_delay_queue(shader_core_ctx_t *shader);
-void shader_unlock_warp(shader_core_ctx_t *shd, std::vector<int> tids, int grid_num);
-
// print out the accumulative statistics for shaders (those that are not local to one shader)
-void shader_print_accstats( FILE* fout );
void shader_print_runtime_stat( FILE *fout );
void shader_print_l1_miss_stat( FILE *fout );
-//return the maximum CTAs that can be running at the same on shader
-//based on on the current kernel's CTA size and is 1 if mutiple CTA per block is not supported
-unsigned int max_cta_per_shader( shader_core_ctx_t *shader);
-
#define TS_IF 0
#define IF_ID 1
#define ID_RR 2
@@ -1011,45 +1284,14 @@ unsigned int max_cta_per_shader( shader_core_ctx_t *shader);
#define EX_MM 4
#define MM_WB 5
#define WB_RT 6
-
#define ID_OC 7
-#define OC_EX_SFU 8
+#define ID_OC_SFU 8
+#define OC_EX_SFU 9
+#define N_PIPELINE_STAGES 10
-#define N_PIPELINE_STAGES 9
-
-extern shader_core_ctx_t **sc;
-extern unsigned int gpgpu_n_load_insn;
-extern unsigned int gpgpu_n_store_insn;
-extern unsigned int gpgpu_n_shmem_insn;
-extern unsigned int gpgpu_n_tex_insn;
-extern unsigned int gpgpu_n_const_insn;
-extern unsigned int gpgpu_multi_unq_fetches;
-extern unsigned int gpgpu_n_cache_bkconflict;
-extern unsigned int gpgpu_n_shmem_bkconflict;
-extern int gpgpu_warpdistro_shader;
extern unsigned int *shader_cycle_distro;
-extern int gpgpu_interwarp_mshr_merge;
-extern unsigned int gpgpu_shmem_size;
-extern unsigned int gpgpu_shader_registers;
-extern unsigned int gpgpu_shader_cta;
-extern bool gpgpu_shmem_bkconflict;
-extern bool gpgpu_cache_bkconflict;
-extern int gpgpu_n_cache_bank;
-extern int pipe_simd_width;
-extern int gpgpu_shmem_port_per_bank;
-extern int gpgpu_cache_port_per_bank;
-extern int gpgpu_const_port_per_bank;
-extern int gpgpu_shmem_pipe_speedup;
-extern bool gpgpu_reg_bank_conflict_model;
-extern unsigned int gpgpu_num_reg_banks;
-extern bool gpgpu_reg_bank_use_warp_id;
-extern unsigned int gpu_max_cta_per_shader;
-extern unsigned int gpu_padded_cta_size;
-extern int gpgpu_local_mem_map;
extern unsigned int n_regconflict_stall;
-extern int gpgpu_coalesce_arch;
-extern unsigned get_max_mshr_used(shader_core_ctx_t* shader);
-extern void mshr_return_from_mem(shader_core_ctx_t * shader, mshr_entry_t* mshr);
-void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc );
+
+int is_store ( const inst_t &op );
#endif /* SHADER_H */
diff --git a/src/gpgpu-sim/stat-tool.cc b/src/gpgpu-sim/stat-tool.cc
index c136d57..af43b72 100644
--- a/src/gpgpu-sim/stat-tool.cc
+++ b/src/gpgpu-sim/stat-tool.cc
@@ -985,12 +985,13 @@ static int s_cache_access_logger_n_types = 0;
static std::vector<linear_histogram_logger> s_cache_access_logger;
enum cache_access_logger_types {
- NORMAL, TEXTURE, CONSTANT
+ NORMAL, TEXTURE, CONSTANT, INSTRUCTION
};
int get_shader_normal_cache_id() { return NORMAL; }
int get_shader_texture_cache_id() { return TEXTURE; }
int get_shader_constant_cache_id() { return CONSTANT; }
+int get_shader_instruction_cache_id() { return INSTRUCTION; }
void shader_cache_access_create( int n_loggers, int n_types, unsigned long long logging_interval)
{
@@ -1010,7 +1011,7 @@ void shader_cache_access_log( int logger_id, int type, int miss)
{
if (s_cache_access_logger_n_types == 0) return;
if (logger_id < 0) return;
- assert(type == NORMAL || type == TEXTURE || type == CONSTANT);
+ assert(type == NORMAL || type == TEXTURE || type == CONSTANT || type == INSTRUCTION);
assert(miss == 0 || miss == 1);
s_cache_access_logger[logger_id].log(2 * type + miss);
@@ -1020,7 +1021,7 @@ void shader_cache_access_unlog( int logger_id, int type, int miss)
{
if (s_cache_access_logger_n_types == 0) return;
if (logger_id < 0) return;
- assert(type == NORMAL || type == TEXTURE || type == CONSTANT);
+ assert(type == NORMAL || type == TEXTURE || type == CONSTANT || type == INSTRUCTION);
assert(miss == 0 || miss == 1);
s_cache_access_logger[logger_id].unlog(2 * type + miss);
diff --git a/src/gpgpu-sim/stat-tool.h b/src/gpgpu-sim/stat-tool.h
index d67daf5..3ebe750 100644
--- a/src/gpgpu-sim/stat-tool.h
+++ b/src/gpgpu-sim/stat-tool.h
@@ -109,6 +109,7 @@ void shader_mem_lat_print( FILE *fout );
int get_shader_normal_cache_id();
int get_shader_texture_cache_id();
int get_shader_constant_cache_id();
+int get_shader_instruction_cache_id();
void shader_cache_access_create( int n_loggers, int n_types, unsigned long long logging_interval );
void shader_cache_access_log( int logger_id, int type, int miss);
void shader_cache_access_unlog( int logger_id, int type, int miss);
diff --git a/src/gpgpu-sim/stats.h b/src/gpgpu-sim/stats.h
new file mode 100644
index 0000000..76e6699
--- /dev/null
+++ b/src/gpgpu-sim/stats.h
@@ -0,0 +1,138 @@
+/*
+ * shader.h
+ *
+ * Copyright (c) 2009 by Tor M. Aamodt 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 STATS_INCLUDED
+#define STATS_INCLUDED
+
+
+
+enum mem_stage_access_type {
+ C_MEM,
+ T_MEM,
+ S_MEM,
+ G_MEM_LD,
+ L_MEM_LD,
+ G_MEM_ST,
+ L_MEM_ST,
+ N_MEM_STAGE_ACCESS_TYPE
+};
+
+enum mem_stage_stall_type {
+ NO_RC_FAIL = 0,
+ BK_CONF,
+ MSHR_RC_FAIL,
+ ICNT_RC_FAIL,
+ COAL_STALL,
+ WB_ICNT_RC_FAIL,
+ WB_CACHE_RSRV_FAIL,
+ N_MEM_STAGE_STALL_TYPE
+};
+
+struct shader_core_stats
+{
+ unsigned int gpgpu_n_load_insn;
+ unsigned int gpgpu_n_store_insn;
+ unsigned int gpgpu_n_shmem_insn;
+ unsigned int gpgpu_n_tex_insn;
+ unsigned int gpgpu_n_const_insn;
+ unsigned int gpgpu_n_param_insn;
+ unsigned int gpgpu_n_shmem_bkconflict;
+ unsigned int gpgpu_n_cache_bkconflict;
+ int gpgpu_n_intrawarp_mshr_merge;
+ unsigned int gpgpu_n_cmem_portconflict;
+ int gpgpu_n_partial_writes;
+ unsigned int gpu_stall_shd_mem_breakdown[N_MEM_STAGE_ACCESS_TYPE][N_MEM_STAGE_STALL_TYPE];
+ unsigned int gpu_reg_bank_conflict_stalls;
+ unsigned int *shader_cycle_distro;
+ unsigned int L1_write_miss;
+ unsigned int L1_read_miss;
+ unsigned int L1_texture_miss;
+ unsigned int L1_const_miss;
+ unsigned int L1_write_hit_on_miss;
+ unsigned int L1_writeback;
+ int *num_warps_issuable;
+ int *num_warps_issuable_pershader;
+ unsigned long long gpu_sim_insn_no_ld_const;
+ unsigned long long gpu_completed_thread;
+ unsigned int gpgpu_commit_pc_beyond_two;
+ unsigned int gpu_stall_by_MSHRwb;
+ unsigned int gpu_stall_shd_mem;
+ unsigned int gpu_stall_sh2icnt;
+ unsigned int *max_return_queue_length;
+
+ //memory access classification
+ int gpgpu_n_mem_read_local;
+ int gpgpu_n_mem_write_local;
+ int gpgpu_n_mem_texture;
+ int gpgpu_n_mem_const;
+ int gpgpu_n_mem_read_global;
+ int gpgpu_n_mem_write_global;
+ int gpgpu_n_mem_read_inst;
+
+ int n_pdom_sc_orig_stat;
+ int n_pdom_sc_single_stat;
+};
+
+#endif
diff --git a/src/gpgpu-sim/visualizer.cc b/src/gpgpu-sim/visualizer.cc
index 69c4452..fd0a422 100644
--- a/src/gpgpu-sim/visualizer.cc
+++ b/src/gpgpu-sim/visualizer.cc
@@ -73,7 +73,6 @@
#include <string.h>
#include <zlib.h>
-static void time_vector_print_interval2file(FILE *outfile);
static void time_vector_print_interval2gzfile(gzFile outfile);
bool g_visualizer_enabled;
@@ -96,13 +95,11 @@ void visualizer_options(option_parser_t opp)
}
-void visualizer_printstat()
+void gpgpu_sim::visualizer_printstat()
{
gzFile visualizer_file = NULL; // gzFile is basically a pointer to a struct, so it is fine to initialize it as NULL
- unsigned i;
if ( !g_visualizer_enabled )
return;
-
// initialize file name if it is not set
if ( g_visualizer_filename == NULL ) {
time_t curr_time;
@@ -131,16 +128,14 @@ void visualizer_printstat()
// instruction count per shader core
gzprintf(visualizer_file, "shaderinsncount: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%u ",sc[i]->num_sim_insn);
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%u ",m_sc[i]->get_num_sim_insn());
gzprintf(visualizer_file, "\n");
// warp divergence per shader core
gzprintf(visualizer_file, "shaderwarpdiv: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%u ", sc[i]->n_diverge);
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%u ", m_sc[i]->get_n_diverge());
gzprintf(visualizer_file, "\n");
cflog_visualizer_gzprint(visualizer_file);
@@ -148,139 +143,82 @@ void visualizer_printstat()
// per shader core cache miss rate
gzprintf(visualizer_file, "CacheMissRate_GlobalLocalL1_All: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1cache, 0));
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1_windowed_cache_miss_rate(0));
gzprintf(visualizer_file, "\n");
-
gzprintf(visualizer_file, "CacheMissRate_TextureL1_All: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1texcache, 0));
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1tex_windowed_cache_miss_rate(0));
gzprintf(visualizer_file, "\n");
-
gzprintf(visualizer_file, "CacheMissRate_ConstL1_All: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1constcache, 0));
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1const_windowed_cache_miss_rate(0));
gzprintf(visualizer_file, "\n");
-
gzprintf(visualizer_file, "CacheMissRate_GlobalLocalL1_noMgHt: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1cache, 1));
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1_windowed_cache_miss_rate(1));
gzprintf(visualizer_file, "\n");
-
gzprintf(visualizer_file, "CacheMissRate_TextureL1_noMgHt: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1texcache, 1));
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1tex_windowed_cache_miss_rate(1));
gzprintf(visualizer_file, "\n");
-
gzprintf(visualizer_file, "CacheMissRate_ConstL1_noMgHt: ");
- for (i=0;i<gpu_n_shader;i++) {
- gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1constcache, 1));
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1const_windowed_cache_miss_rate(1));
gzprintf(visualizer_file, "\n");
// reset for next interval
- for (i=0;i<gpu_n_shader;i++) {
- shd_cache_new_window(sc[i]->L1cache);
- shd_cache_new_window(sc[i]->L1texcache);
- shd_cache_new_window(sc[i]->L1constcache);
- }
-
- // dram specific statistics
- for (i=0;i<gpu_n_mem;i++) {
- gzprintf(visualizer_file, "dramncmd: %u %u\n",dram[i]->id, dram[i]->n_cmd_partial);
- gzprintf(visualizer_file, "dramnop: %u %u\n",dram[i]->id,dram[i]->n_nop_partial);
- gzprintf(visualizer_file,"dramnact: %u %u\n",dram[i]->id,dram[i]->n_act_partial);
- gzprintf(visualizer_file,"dramnpre: %u %u\n",dram[i]->id,dram[i]->n_pre_partial);
- gzprintf(visualizer_file,"dramnreq: %u %u\n",dram[i]->id,dram[i]->n_req_partial);
- gzprintf(visualizer_file,"dramavemrqs: %u %u\n",dram[i]->id,
- dram[i]->n_cmd_partial?(dram[i]->ave_mrqs_partial/dram[i]->n_cmd_partial ):0);
-
- // utilization and efficiency
- gzprintf(visualizer_file,"dramutil: %u %u\n",
- dram[i]->id,dram[i]->n_cmd_partial?100*dram[i]->bwutil_partial/dram[i]->n_cmd_partial:0);
- gzprintf(visualizer_file,"drameff: %u %u\n",
- dram[i]->id,dram[i]->n_activity_partial?100*dram[i]->bwutil_partial/dram[i]->n_activity_partial:0);
-
- // reset for next interval
- dram[i]->bwutil_partial = 0;
- dram[i]->n_activity_partial = 0;
- dram[i]->ave_mrqs_partial = 0;
- dram[i]->n_cmd_partial = 0;
- dram[i]->n_nop_partial = 0;
- dram[i]->n_act_partial = 0;
- dram[i]->n_pre_partial = 0;
- dram[i]->n_req_partial = 0;
- }
+ for (unsigned i=0;i<m_n_shader;i++)
+ m_sc[i]->new_cache_window();
- // dram access type classification
- for (i=0;i<gpu_n_mem;i++) {
- unsigned int j;
- for (j = 0; j < gpu_mem_n_bk; j++) {
- gzprintf(visualizer_file,"dramglobal_acc_r: %u %u %u\n", dram[i]->id, j,
- mem_access_type_stats[GLOBAL_ACC_R][dram[i]->id][j]);
- gzprintf(visualizer_file,"dramglobal_acc_w: %u %u %u\n", dram[i]->id, j,
- mem_access_type_stats[GLOBAL_ACC_W][dram[i]->id][j]);
- gzprintf(visualizer_file,"dramlocal_acc_r: %u %u %u\n", dram[i]->id, j,
- mem_access_type_stats[LOCAL_ACC_R][dram[i]->id][j]);
- gzprintf(visualizer_file,"dramlocal_acc_w: %u %u %u\n", dram[i]->id, j,
- mem_access_type_stats[LOCAL_ACC_W][dram[i]->id][j]);
- gzprintf(visualizer_file,"dramconst_acc_r: %u %u %u\n", dram[i]->id, j,
- mem_access_type_stats[CONST_ACC_R][dram[i]->id][j]);
- gzprintf(visualizer_file,"dramtexture_acc_r: %u %u %u\n", dram[i]->id, j,
- mem_access_type_stats[TEXTURE_ACC_R][dram[i]->id][j]);
- }
- }
+ for (unsigned i=0;i<m_n_mem;i++)
+ m_memory_partition_unit[i]->visualizer_print(visualizer_file);
// overall cache miss rates
- gzprintf(visualizer_file, "Lonetexturemiss: %d\n", L1_texture_miss);
- gzprintf(visualizer_file, "Loneconstmiss: %d\n", L1_const_miss);
- gzprintf(visualizer_file, "Lonereadmiss: %d\n", L1_read_miss);
- gzprintf(visualizer_file, "Lonewritemiss: %d\n", L1_write_miss);
- gzprintf(visualizer_file, "Ltwowritemiss: %d\n", L2_write_miss);
- gzprintf(visualizer_file, "Ltwowritehit: %d\n", L2_write_hit);
- gzprintf(visualizer_file, "Ltworeadmiss: %d\n", L2_read_miss);
- gzprintf(visualizer_file, "Ltworeadhit: %d\n", L2_read_hit);
+ gzprintf(visualizer_file, "Lonetexturemiss: %d\n", m_shader_stats->L1_texture_miss);
+ gzprintf(visualizer_file, "Loneconstmiss: %d\n", m_shader_stats->L1_const_miss);
+ gzprintf(visualizer_file, "Lonereadmiss: %d\n", m_shader_stats->L1_read_miss);
+ gzprintf(visualizer_file, "Lonewritemiss: %d\n", m_shader_stats->L1_write_miss);
+ gzprintf(visualizer_file, "Ltwowritemiss: %d\n", m_memory_stats->L2_write_miss);
+ gzprintf(visualizer_file, "Ltwowritehit: %d\n", m_memory_stats->L2_write_hit);
+ gzprintf(visualizer_file, "Ltworeadmiss: %d\n", m_memory_stats->L2_read_miss);
+ gzprintf(visualizer_file, "Ltworeadhit: %d\n", m_memory_stats->L2_read_hit);
// latency stats
- if (num_mfs) {
- gzprintf(visualizer_file, "averagemflatency: %lld\n", mf_total_lat/num_mfs);
+ if (m_memory_stats->num_mfs) {
+ gzprintf(visualizer_file, "averagemflatency: %lld\n", m_memory_stats->mf_total_lat/m_memory_stats->num_mfs);
}
// other parameters for graphing
gzprintf(visualizer_file, "globalcyclecount: %lld\n", gpu_sim_cycle);
gzprintf(visualizer_file, "globalinsncount: %lld\n", gpu_sim_insn);
gzprintf(visualizer_file, "globaltotinsncount: %lld\n", gpu_tot_sim_insn);
- gzprintf(visualizer_file, "gpucompletedthreads: %lld\n", gpu_completed_thread);
+ gzprintf(visualizer_file, "gpucompletedthreads: %lld\n", m_shader_stats->gpu_completed_thread);
gzprintf(visualizer_file, "gpgpunsentwrites: %d\n", gpgpu_n_sent_writes);
gzprintf(visualizer_file, "gpgpunprocessedwrites: %d\n", gpgpu_n_processed_writes);
- gzprintf(visualizer_file, "gpgpu_n_cache_bkconflict: %d\n", gpgpu_n_cache_bkconflict);
- gzprintf(visualizer_file, "gpgpu_n_shmem_bkconflict: %d\n", gpgpu_n_shmem_bkconflict);
- gzprintf(visualizer_file, "gpu_stall_by_MSHRwb: %d\n", gpu_stall_by_MSHRwb);
+ gzprintf(visualizer_file, "gpgpu_n_cache_bkconflict: %d\n", m_shader_stats->gpgpu_n_cache_bkconflict);
+ gzprintf(visualizer_file, "gpgpu_n_shmem_bkconflict: %d\n", m_shader_stats->gpgpu_n_shmem_bkconflict);
+ gzprintf(visualizer_file, "gpu_stall_by_MSHRwb: %d\n", m_shader_stats->gpu_stall_by_MSHRwb);
// warp divergence breakdown
static unsigned int *last_shader_cycle_distro = NULL;
if (!last_shader_cycle_distro)
- last_shader_cycle_distro = (unsigned int*) calloc(warp_size + 3, sizeof(unsigned int));
+ last_shader_cycle_distro = (unsigned int*) calloc(m_shader_config->warp_size + 3, sizeof(unsigned int));
time_vector_print_interval2gzfile(visualizer_file);
gzprintf(visualizer_file, "WarpDivergenceBreakdown:");
unsigned int total=0;
- unsigned int cf = (gpgpu_warpdistro_shader==-1)?gpu_n_shader:1;
- gzprintf(visualizer_file, " %d", (shader_cycle_distro[0] - last_shader_cycle_distro[0]) / cf );
- gzprintf(visualizer_file, " %d", (shader_cycle_distro[2] - last_shader_cycle_distro[2]) / cf );
- for (i=0; i<warp_size+3; i++) {
+ unsigned int cf = (m_shader_config->gpgpu_warpdistro_shader==-1)?m_n_shader:1;
+ gzprintf(visualizer_file, " %d", (m_shader_stats->shader_cycle_distro[0] - last_shader_cycle_distro[0]) / cf );
+ gzprintf(visualizer_file, " %d", (m_shader_stats->shader_cycle_distro[2] - last_shader_cycle_distro[2]) / cf );
+ for (unsigned i=0; i<m_shader_config->warp_size+3; i++) {
if ( i>=3 ) {
- total += (shader_cycle_distro[i] - last_shader_cycle_distro[i]);
- if ( ((i-3) % (warp_size/8)) == ((warp_size/8)-1) ) {
+ total += (m_shader_stats->shader_cycle_distro[i] - last_shader_cycle_distro[i]);
+ if ( ((i-3) % (m_shader_config->warp_size/8)) == ((m_shader_config->warp_size/8)-1) ) {
gzprintf(visualizer_file, " %d", total / cf );
total=0;
}
}
- last_shader_cycle_distro[i] = shader_cycle_distro[i];
+ last_shader_cycle_distro[i] = m_shader_stats->shader_cycle_distro[i];
}
gzprintf(visualizer_file,"\n");
@@ -535,12 +473,6 @@ void time_vector_print(void) {
g_my_time_vector->print_dist();
}
-
-void time_vector_print_interval2file(FILE *outfile) {
- g_my_time_vector->print_to_file(outfile);
-}
-
-
void time_vector_print_interval2gzfile(gzFile outfile) {
g_my_time_vector->print_to_gzfile(outfile);
}
diff --git a/src/gpgpu-sim/visualizer.h b/src/gpgpu-sim/visualizer.h
index 19e2d2a..0d9424a 100644
--- a/src/gpgpu-sim/visualizer.h
+++ b/src/gpgpu-sim/visualizer.h
@@ -66,7 +66,7 @@
#include <zlib.h>
void visualizer_options(class OptionParser *opp);
-void visualizer_printstat();
+void visualizer_printstat( class shader_core_ctx **sc, unsigned n_shader, class dram_t **dram, unsigned n_mem );
void time_vector_create(int ld_size,int st_size);
void time_vector_print(void);
void time_vector_update(unsigned int uid,int slot ,long int cycle,int type);
diff --git a/src/gpgpu-sim/warp_tracker.cc b/src/gpgpu-sim/warp_tracker.cc
index d701c8f..44cbbc6 100644
--- a/src/gpgpu-sim/warp_tracker.cc
+++ b/src/gpgpu-sim/warp_tracker.cc
@@ -70,87 +70,22 @@
using namespace std;
-
-void register_cta_thread_exit(shader_core_ctx_t *shader, int cta_num );
-
/*
* 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 *shd Pointer to the shader core
- *
- * @return Pointer to a warp_tracker
- */
-warp_tracker_pool::warp_tracker_pool(unsigned gpu_n_shader, unsigned gpu_n_thread_per_shader) {
- this->gpu_n_shader = gpu_n_shader;
- this->gpu_n_thread_per_shader = gpu_n_thread_per_shader;
-
- // Resize the warp tracker map
- warp_tracker_map.resize(gpu_n_shader);
- for(unsigned i=0; i<gpu_n_shader; i++) {
- warp_tracker_map[i].resize(gpu_n_thread_per_shader);
- }
-
- // Create a pool of warp_trackers
- warp_tracker_list.resize(gpu_n_shader * gpu_n_thread_per_shader);
-
- // Add all warp_trackers to the list of free warp_trackers
- std::list<warp_tracker>::iterator it;
- for(it=warp_tracker_list.begin(); it!=warp_tracker_list.end(); it++)
- warp_tracker_free_list.push_back(&(*it));
-
-}
-
-/*
- * Fetch a free warp_tracker from the pool of warp_trackers. Assigns the warp_tracker to
- * the input warp.
- *
- * If there are no free warp_trackers in the pool, the pool is extended by allocating more
- * warp_trackers.
- *
- * @param tid_in Array of thread id's corresponding to a warp
- * @param *shd Pointer to the shader core
- *
- * @return Pointer to a warp_tracker
- */
-warp_tracker* warp_tracker_pool::alloc_warp_tracker( int *tid_in, shader_core_ctx_t *shd, address_type pc ) {
- // If no free warp trackers are available, allocate some more
- if(warp_tracker_free_list.empty()) {
- printf("warp_tracker_list empty (size=%d) - allocating new warp_trackers\n", size());
- fflush(stdout);
- // Warp tracker list is empty, resize the list
- unsigned previous_size = warp_tracker_list.size();
- warp_tracker_list.resize( previous_size + this->gpu_n_thread_per_shader);
-
- // Add newly allocated warp trackers to list of free warp trackers
- std::list<warp_tracker>::iterator it = warp_tracker_list.begin();
- for(unsigned i=0; i<previous_size; i++)
- it++; // Increment iterator
- for(; it!=warp_tracker_list.end(); it++)
- warp_tracker_free_list.push_back(&(*it));
- }
-
- assert(!warp_tracker_free_list.empty());
- // Fetch a free warp_tracker
- warp_tracker* wpt = warp_tracker_free_list.front();
- warp_tracker_free_list.pop_front();
- wpt->set_warp(tid_in, shd, pc);
-
- return wpt;
-}
-
-/*
- * Free the warp_tracker.
- *
- * Puts the warp_tracker back into the pool of free warp_trackers.
- *
- * @param wpt Pointer to a warp_tracker
+ * @param *my_shader Pointer to the shader core
*
*/
-void warp_tracker_pool::free_warp_tracker(warp_tracker* wpt) {
- warp_tracker_free_list.push_back(wpt);
+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);
}
/*
@@ -163,24 +98,15 @@ void warp_tracker_pool::free_warp_tracker(warp_tracker* wpt) {
* @param *shd Pointer to the shader core
*
*/
-void warp_tracker_pool::wpt_register_warp( int *tid_in, shader_core_ctx_t *shd, address_type pc)
+void warp_tracker_pool::wpt_register_warp( int *tid_in, address_type pc, unsigned n_thd, unsigned warp_size )
{
- int sid = shd->sid;
- unsigned i;
- int n_thd = 0;
- for (i=0; i<warp_size; i++) {
- if (tid_in[i] >= 0) n_thd++;
- }
-
- if (!n_thd) return;
-
- warp_tracker *wpt = this->alloc_warp_tracker(tid_in, shd, pc);
-
+ assert(n_thd);
+ warp_tracker *wpt = new warp_tracker(tid_in,pc,warp_size);
// assign the new warp_tracker to warp_tracker_map
- for (i=0; i<warp_size; i++) {
+ for (unsigned i=0; i<warp_size; i++) {
if (tid_in[i] >= 0) {
- assert( map_get_warp_tracker(sid,tid_in[i],pc) == NULL );
- map_set_warp_tracker(sid, tid_in[i], pc, wpt);
+ assert( map_get_warp_tracker(tid_in[i],pc) == NULL );
+ map_set_warp_tracker(tid_in[i], pc, wpt);
}
}
}
@@ -193,10 +119,9 @@ void warp_tracker_pool::wpt_register_warp( int *tid_in, shader_core_ctx_t *shd,
*
* @return Returns true is all threads in the warp have completed.
*/
-int warp_tracker_pool::wpt_signal_avail( int tid, shader_core_ctx_t *shd, address_type pc )
+int warp_tracker_pool::wpt_signal_avail( int tid, address_type pc )
{
- int sid = shd->sid;
- warp_tracker *wpt = map_get_warp_tracker(sid,tid,pc);
+ warp_tracker *wpt = map_get_warp_tracker(tid,pc);
assert(wpt != NULL);
@@ -215,22 +140,13 @@ int warp_tracker_pool::wpt_signal_avail( int tid, shader_core_ctx_t *shd, addres
* by number of active threads.
*
* @param tid Thread that is exiting
- * @param *shd Pointer to the shader core
*
*/
-void warp_tracker_pool::wpt_deregister_warp( int tid, shader_core_ctx_t *shd, address_type pc ) {
- int sid = shd->sid;
- warp_tracker *wpt = map_get_warp_tracker(sid,tid,pc);
+void warp_tracker_pool::wpt_deregister_warp( int tid, address_type pc ) {
+ warp_tracker *wpt = map_get_warp_tracker(tid,pc);
assert(wpt != NULL);
-
- // the warp is ready to be fetched again, remove this warp_tracker
- for (unsigned i=0; i<warp_size; i++) {
- if (wpt->tid[i] >= 0) {
- map_clear_warp_tracker(sid,wpt->tid[i],pc);
- }
- }
-
- free_warp_tracker( wpt );
+ map_clear_warp_tracker(wpt);
+ delete wpt;
}
@@ -241,30 +157,26 @@ void warp_tracker_pool::wpt_deregister_warp( int tid, shader_core_ctx_t *shd, ad
* threads and removed the warp from warp tracker.
*
* @param tid Thread that is exiting
- * @param *shd Pointer to the shader core
*
* @return The warp's mask of active threads.
*/
-int warp_tracker_pool::wpt_signal_complete( int tid, shader_core_ctx_t *shd, address_type pc )
+int warp_tracker_pool::wpt_signal_complete( int tid, address_type pc )
{
- int sid = shd->sid;
- warp_tracker *wpt = map_get_warp_tracker(sid,tid,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) {
- register_cta_thread_exit(shd, wpt->tid[i] );
- map_clear_warp_tracker(sid,wpt->tid[i],pc);
+ if (wpt->tid(i) >= 0) {
+ m_shader->register_cta_thread_exit( wpt->tid(i) );
warp_mask |= (1 << i);
}
}
-
- free_warp_tracker( wpt );
-
+ delete wpt;
return warp_mask;
} else {
return 0;
@@ -276,373 +188,84 @@ int warp_tracker_pool::wpt_signal_complete( int tid, shader_core_ctx_t *shd, add
*
* Checks if any pc of the given tid maps to a warp_tracker
*
- * @param *shd Pointer to the shader core
* @param tid Thread to check
*
* @return True is thread is being tracked
*/
-bool warp_tracker_pool::wpt_thread_in_wpt(shader_core_ctx *shd, int tid) {
- int sid = shd->sid;
+bool warp_tracker_pool::wpt_thread_in_wpt(int tid) {
std::map<address_type, warp_tracker*>::iterator it;
- for(it=warp_tracker_map[sid][tid].begin(); it!=warp_tracker_map[sid][tid].end(); it++)
+ for(it=warp_tracker_map[tid].begin(); it!=warp_tracker_map[tid].end(); it++)
if((*it).second != NULL)
return true;
return false;
}
-
-
-warp_tracker_pool& get_warp_tracker_pool(){
- static warp_tracker_pool* wpt_pool = new warp_tracker_pool(gpu_n_shader, gpu_n_thread_per_shader);
- return *wpt_pool;
-}
-
-
-//-------------------------------------------------------------------------------
-
-/*
-
-static warp_tracker ***warp_tracker_map;
-static unsigned **g_warp_tracker_map_setl_cycle;
-static warp_tracker *warp_tracker_pool = NULL;
-static list<warp_tracker*> free_wpt;
-
-warp_tracker* alloc_warp_tracker( int *tid_in, shader_core_ctx_t *shd )
-{
- assert(!free_wpt.empty());
- warp_tracker* wpt = free_wpt.front();
- free_wpt.pop_front();
-
- wpt->set_warp(tid_in, shd);
-
- return wpt;
-}
-
-void free_warp_tracker(warp_tracker* wpt)
-{
- free_wpt.push_back(wpt);
-}
-
-void init_warp_tracker( )
-{
- unsigned int i;
-
- warp_tracker_map = (warp_tracker ***)calloc(gpu_n_shader, sizeof(warp_tracker **));
- g_warp_tracker_map_setl_cycle = (unsigned**)calloc(gpu_n_shader, sizeof(unsigned*));
- for (i=0; i<gpu_n_shader; i++) {
- warp_tracker_map[i] = (warp_tracker **)calloc(gpu_n_thread_per_shader, sizeof(warp_tracker *));
- g_warp_tracker_map_setl_cycle[i] = (unsigned*)calloc(gpu_n_thread_per_shader, sizeof(unsigned));
- }
-
- // max possible number of warps is just when each thread has its own warp
- warp_tracker_pool = new warp_tracker[gpu_n_shader * gpu_n_thread_per_shader];
- printf("%d %d %d %d\n", warp_size, gpu_n_shader, gpu_n_thread_per_shader,
- warp_size * gpu_n_shader * gpu_n_thread_per_shader);
- for (i=0; i<gpu_n_shader*gpu_n_thread_per_shader; i++) {
- free_wpt.push_back(&(warp_tracker_pool[i]));
- }
- printf("%zd\n", free_wpt.size());
-}
-
-void wpt_register_warp( int *tid_in, shader_core_ctx_t *shd )
-{
- int sid = shd->sid;
- unsigned i;
- int n_thd = 0;
- for (i=0; i<warp_size; i++) {
- if (tid_in[i] >= 0) n_thd++;
- }
-
- if (!n_thd) return;
-
- warp_tracker *wpt = alloc_warp_tracker(tid_in, shd);
-
- // assign the new warp_tracker to warp_tracker_map
- for (i=0; i<warp_size; i++) {
- if (tid_in[i] >= 0) {
- assert( warp_tracker_map[sid][tid_in[i]] == NULL );
- warp_tracker_map[sid][tid_in[i]] = wpt;
- g_warp_tracker_map_setl_cycle[sid][tid_in[i]] = gpu_tot_sim_cycle + gpu_sim_cycle;
- }
- }
-}
-
-int wpt_signal_avail( int tid, shader_core_ctx_t *shd )
-{
- int sid = shd->sid;
- warp_tracker *wpt = warp_tracker_map[sid][tid];
- assert(wpt != NULL);
-
-
- // signal the warp tracker
- if (wpt->avail_thd()) {
- return 1;
- } else {
- return 0;
- }
-}
-
-// Unlock a warp
-void wpt_unlock_threads( int tid, shader_core_ctx_t *shd ) {
- int sid = shd->sid;
- warp_tracker *wpt = warp_tracker_map[sid][tid];
- assert(wpt != NULL);
-
- int thd_unlocked = 0;
- // Unlock
- for (unsigned i=0; i<warp_size; i++) {
- if (wpt->tid[i] >= 0) {
- shd->thread[wpt->tid[i]].avail4fetch++;
- assert(shd->thread[wpt->tid[i]].avail4fetch <= 1);
- assert( shd->warp[wpt->tid[i]/warp_size].n_avail4fetch < warp_size );
- shd->warp[wpt->tid[i]/warp_size].n_avail4fetch++;
- thd_unlocked = 1;
- }
- }
-
- if (shd->model == POST_DOMINATOR || shd->model == NO_RECONVERGE) {
- // Do nothing
- } else {
- // For this case, submit to commit_queue
- if (shd->using_commit_queue && thd_unlocked) {
- int *tid_unlocked = alloc_commit_warp();
- memcpy(tid_unlocked, wpt->tid, sizeof(int)*warp_size);
- dq_push(shd->thd_commit_queue,(void*)tid_unlocked);
- }
- }
-
- // the warp is ready to be fetched again, remove this warp_tracker
- for (unsigned i=0; i<warp_size; i++) {
- if (wpt->tid[i] >= 0) {
- warp_tracker_map[sid][wpt->tid[i]] = NULL;
- g_warp_tracker_map_setl_cycle[sid][wpt->tid[i]] = gpu_tot_sim_cycle + gpu_sim_cycle;
- }
- }
-
- free_warp_tracker( 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
- * @param *shd Pointer to the shader core
- *
- * @return The warp's mask of active threads.
- */
-//
-
-/*
-int wpt_signal_complete( int tid, shader_core_ctx_t *shd )
-{
- int sid = shd->sid;
- warp_tracker *wpt = warp_tracker_map[sid][tid];
- assert(wpt != NULL);
-
- // signal the warp tracker
- if (wpt->complete_thd(tid)) {
- // if the warp has completed execution, remove this warp_tracker
- int warp_mask = 0;
- for (unsigned i=0; i<warp_size; i++) {
- if (wpt->tid[i] >= 0) {
- register_cta_thread_exit(shd, wpt->tid[i] );
- warp_tracker_map[sid][wpt->tid[i]] = NULL;
- g_warp_tracker_map_setl_cycle[sid][wpt->tid[i]] = gpu_tot_sim_cycle + gpu_sim_cycle;
- warp_mask |= (1 << i);
- }
- }
-
- free_warp_tracker( wpt );
-
- return warp_mask;
- } else {
- return 0;
- }
-}
-*/
-
//------------------------------------------------------------------------------------
-class thread_pc_tracker_class {
-public:
- address_type *thd_pc; // tracks the pc of each thread
- map<address_type, unsigned> pc_count;
- unsigned acc_pc_count;
- int simd_width;
- static map<unsigned, unsigned> histogram;
-
- thread_pc_tracker_class( ) {
- this->acc_pc_count = 0;
- this->simd_width = 0;
- this->thd_pc = NULL;
- }
-
- thread_pc_tracker_class(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
- 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");
- }
-};
-
-map<unsigned, unsigned> thread_pc_tracker_class::histogram;
+map<unsigned, unsigned> thread_pc_tracker::histogram;
-thread_pc_tracker_class *thread_pc_tracker = NULL;
+thread_pc_tracker *thread_pc_tracker = NULL;
void print_thread_pc_histogram( FILE *fout )
{
- thread_pc_tracker_class::histo_print(fout);
+ thread_pc_tracker::histo_print(fout);
}
-void print_thread_pc( FILE *fout )
+void print_thread_pc( FILE *fout, unsigned n_shader )
{
fprintf(fout, "SHD_PC_C: ");
- for (unsigned i=0; i<gpu_n_shader; i++) {
+ for (unsigned i=0; i<n_shader; i++) {
fprintf(fout, "%d ", thread_pc_tracker[i].get_acc_pc_count() );
}
fprintf(fout, "\n");
}
-void track_thread_pc( int shader_id, int *tid, address_type pc )
-{
- if (!thread_pc_tracker) {
- thread_pc_tracker = new thread_pc_tracker_class[gpu_n_shader];
- for (unsigned i=0; i<gpu_n_shader; i++) {
- thread_pc_tracker[i] = thread_pc_tracker_class(warp_size, gpu_n_thread_per_shader);
- }
- }
- thread_pc_tracker[shader_id].set_threads_pc( tid, pc );
-}
-
-//------------------------------------------------------------------------------------
-
-static int *commit_warp_pool = NULL;
-static queue<int*> free_commit_warp_q;
-
-void init_commit_warp( )
-{
- unsigned int num_warp = warp_size * gpu_n_shader * gpu_n_thread_per_shader;
- commit_warp_pool = new int[num_warp];
- for (unsigned int i=0; i<num_warp; i+=warp_size) {
- free_commit_warp_q.push(&(commit_warp_pool[i]));
- }
-}
-
-int* alloc_commit_warp( )
-{
- if (!commit_warp_pool) {
- init_commit_warp( );
- }
-
- assert(!free_commit_warp_q.empty());
- int *new_commit_warp = free_commit_warp_q.front();
- free_commit_warp_q.pop();
-
- return new_commit_warp;
-}
-
-void free_commit_warp( int *commit_warp )
-{
- free_commit_warp_q.push(commit_warp);
-}
-
// uncomment to enable checking for warp consistency
// #define CHECK_WARP_CONSISTENCY
-void check_stage_pcs( shader_core_ctx_t *shader, unsigned stage )
+void shader_core_ctx::check_stage_pcs( unsigned stage )
{
#ifdef CHECK_WARP_CONSISTENCY
address_type inst_pc = (address_type)-1;
unsigned tid;
- if( shader->model == MIMD )
+ if( m_config->model == MIMD )
return;
std::set<unsigned> tids;
- for ( int i = 0; i < pipe_simd_width; i++) {
- if (shader->pipeline_reg[i][stage].hw_thread_id == -1 )
+ 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 = shader->pipeline_reg[i][stage].pc;
- tid = shader->pipeline_reg[i][stage].hw_thread_id;
+ 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 == shader->pipeline_reg[i][stage].pc );
+ assert( inst_pc == m_pipeline_reg[i][stage].pc );
}
#endif
}
-void check_pm_stage_pcs( shader_core_ctx_t *shader, unsigned stage )
+void shader_core_ctx::check_pm_stage_pcs( unsigned stage )
{
#ifdef CHECK_WARP_CONSISTENCY
address_type inst_pc = (address_type)-1;
unsigned tid;
- if( shader->model == MIMD )
+ if( m_config->model == MIMD )
return;
std::set<unsigned> tids;
- for (int i = 0; i < pipe_simd_width; i++) {
- if (shader->pre_mem_pipeline[i][stage].hw_thread_id == -1 )
+ 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 = shader->pre_mem_pipeline[i][stage].pc;
- tid = shader->pre_mem_pipeline[i][stage].hw_thread_id;
+ 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 == shader->pre_mem_pipeline[i][stage].pc );
+ 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
index 1e2e5e0..8397a81 100644
--- a/src/gpgpu-sim/warp_tracker.h
+++ b/src/gpgpu-sim/warp_tracker.h
@@ -63,176 +63,199 @@
* Vancouver, BC V6T 1Z4
*/
-#include <vector>
-#include <map>
-#include <list>
-
#ifndef warp_tracker_h_INCLUDED
#define warp_tracker_h_INCLUDED
-#ifdef __cplusplus
-
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <cassert>
- #include <map>
- #include <list>
- #include <deque>
- #include <queue>
-
-#endif
+#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"
-extern unsigned int warp_size;
-extern unsigned int gpu_n_shader;
-extern unsigned int gpu_n_thread_per_shader;
-
-//void init_warp_tracker( );
-
-//void wpt_register_warp( int *tid_in, shader_core_ctx_t *shd );
-
-//int wpt_signal_avail( int tid, shader_core_ctx_t *shd );
-
-//void wpt_unlock_threads( int tid, shader_core_ctx_t *shd );
-
-//int wpt_signal_complete( int tid, shader_core_ctx_t *shd );
-
void print_thread_pc_histogram( FILE *fout );
-void print_thread_pc( FILE *fout );
-void track_thread_pc( int shader_id, int *tid, address_type pc );
-
-int* alloc_commit_warp( );
-void free_commit_warp( int *commit_warp );
+void print_thread_pc( FILE *fout, unsigned n_shader );
class warp_tracker {
public:
- std::vector<int> tid;
-
- int n_thd; // total number of threads in this warp
- int n_notavail; // number of threads still not available
- shader_core_ctx_t *shd; // reference to shader core
- address_type pc;
-
- warp_tracker () {
- tid.resize(warp_size,-1);
-
- n_thd = 0;
- n_notavail = 0;
- shd = NULL;
+ 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(){
- printf("sid=%d ", shd->sid);
-
- printf("tid=[");
- for(unsigned i=0; i<warp_size; i++)
- if(tid[i] > -1)
- printf("%d ", tid[i]);
+ 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]; }
- void copy_tid( int *tid ) {
- std::copy(tid, tid+warp_size, this->tid.begin());
+ 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);
}
- // set the warp to be consist of the given threads
- void set_warp ( int *tid, shader_core_ctx_t *shd, address_type pc) {
- copy_tid(tid);
-
- this->n_thd = 0;
- this->n_notavail = 0;
- for (unsigned i=0; i<warp_size; i++) {
- if (this->tid[i] >= 0) {
- this->n_thd++;
- }
- }
- this->n_notavail = this->n_thd;
- this->shd = shd;
- this->pc = pc;
- }
-
- // signal that this thread is available for fetch
- // if all threads in the warp are available, change all their status
- // and return true
- bool avail_thd ( ) {
- n_notavail--;
- return (n_notavail==0);
- }
-
- // a bookkeeping method to allow a warp to be deallocated
- // when its threads have finished executing.
- bool complete_thd ( int tid_in ) {
- n_notavail--;
- if (n_notavail) {
+ 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
-{
- private:
- unsigned gpu_n_shader;
- unsigned gpu_n_thread_per_shader;
+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 );
- // Warp tracker map: a vector (index shader id) of vectors (index thread id) of maps (index pc)
- std::vector< std::vector< std::map<address_type, warp_tracker*> > > warp_tracker_map;
+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];
+ }
- // Pool of warp trackers
- std::list<warp_tracker> warp_tracker_list;
+ 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;
+ }
- // List to keep track of free warp trackers
- std::list<warp_tracker*> warp_tracker_free_list;
+ 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;
+ }
+ }
+ }
- warp_tracker* map_get_warp_tracker(int sid, int tid, address_type pc) {
- // Return NULL pointer if no warp_tracker assigned
- if(warp_tracker_map[sid][tid].find(pc) == warp_tracker_map[sid][tid].end())
- return NULL;
+// data
- return warp_tracker_map[sid][tid][pc];
- }
+ class shader_core_ctx *m_shader;
+ unsigned gpu_n_thread_per_shader;
+ unsigned warp_size;
- void map_set_warp_tracker(int sid, int tid, address_type pc, warp_tracker* wpt) {
- // Make sure that warp tracker is not already assigned here
- if(warp_tracker_map[sid][tid].find(pc) != warp_tracker_map[sid][tid].end())
- assert(warp_tracker_map[sid][tid][pc] == NULL);
+ // 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
- warp_tracker_map[sid][tid][pc] = wpt;
- }
+ thread_pc_tracker( ) {
+ this->acc_pc_count = 0;
+ this->simd_width = 0;
+ this->thd_pc = NULL;
+ }
- void map_clear_warp_tracker(int sid, int tid, address_type pc) {
- // Make sure that warp tracker was previously assigned
- assert(warp_tracker_map[sid][tid].find(pc) != warp_tracker_map[sid][tid].end());
- assert(warp_tracker_map[sid][tid][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);
+ }
- warp_tracker_map[sid][tid][pc] = NULL;
- }
+ 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;
+ }
+ }
+ }
- warp_tracker* alloc_warp_tracker( int *tid_in, shader_core_ctx_t *shd, address_type pc );
- void free_warp_tracker(warp_tracker* wpt);
+ 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
+ }
+ }
+ }
- public:
- warp_tracker_pool( unsigned gpu_n_shader, unsigned gpu_n_thread_per_shader );
+ void update_acc_count( ) {
+ acc_pc_count += pc_count.size();
+ histogram[pc_count.size()] += 1;
+ }
- void wpt_register_warp( int *tid_in, shader_core_ctx_t *shd, address_type pc );
- int wpt_signal_avail( int tid, shader_core_ctx_t *shd, address_type pc );
- void wpt_deregister_warp( int tid, shader_core_ctx_t *shd, address_type pc );
- int wpt_signal_complete( int tid, shader_core_ctx_t *shd, address_type pc );
+ void set_threads_pc ( int *tid, address_type pc ) {
+ sub_threads(tid);
+ add_threads(tid, pc);
+ update_acc_count( );
+ }
- unsigned size() { return warp_tracker_list.size(); }
- unsigned free_size() { return warp_tracker_free_list.size(); }
+ unsigned get_acc_pc_count( ) { return acc_pc_count;}
- bool wpt_thread_in_wpt(shader_core_ctx *shd, int tid);
+ 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");
+ }
};
-warp_tracker_pool& get_warp_tracker_pool();
-
#endif
diff --git a/src/gpgpusim_entrypoint.cc b/src/gpgpusim_entrypoint.cc
index 5cd7d7f..fe5d112 100644
--- a/src/gpgpusim_entrypoint.cc
+++ b/src/gpgpusim_entrypoint.cc
@@ -72,23 +72,47 @@
#include "gpgpu-sim/gpu-sim.h"
#include "gpgpu-sim/icnt_wrapper.h"
+#include <pthread.h>
+#include <semaphore.h>
+
#define MAX(a,b) (((a)>(b))?(a):(b))
-struct gpgpu_ptx_sim_arg *grid_params;
-static int sg_grid_num=0;
static int sg_argc = 3;
static const char *sg_argv[] = {"", "-config","gpgpusim.config"};
+struct gpgpu_ptx_sim_arg *grid_params;
+
+sem_t g_sim_signal_start;
+sem_t g_sim_signal_finish;
time_t g_simulation_starttime;
+pthread_t g_simulation_thread;
-void gpgpu_ptx_sim_init_perf()
+gpgpu_sim g_the_gpu;
+
+static void print_simulation_time();
+
+void *gpgpu_sim_thread(void*)
+{
+ do {
+ sem_wait(&g_sim_signal_start);
+ unsigned grid;
+ class function_info *entry;
+ g_the_gpu.next_grid(grid,entry);
+ g_the_gpu.run_gpu_sim();
+ print_simulation_time();
+ sem_post(&g_sim_signal_finish);
+ } while(1);
+ return NULL;
+}
+
+gpgpu_sim *gpgpu_ptx_sim_init_perf()
{
print_splash();
read_sim_environment_variables();
read_parser_environment_variables();
option_parser_t opp = option_parser_create();
icnt_reg_options(opp);
- gpu_reg_options(opp); // register GPU microrachitecture options
+ g_the_gpu.reg_options(opp); // register GPU microrachitecture options
ptx_reg_options(opp);
option_parser_cmdline(opp, sg_argc, sg_argv); // parse configuration options
@@ -101,14 +125,19 @@ void gpgpu_ptx_sim_init_perf()
fprintf(stdout, "GPGPU-Sim: Configuration options:\n\n");
option_parser_print(opp, stdout);
- init_gpu();
- fprintf(stdout, "GPU performance model initialization complete.\n");
+
+ g_the_gpu.init_gpu();
g_simulation_starttime = time((time_t *)NULL);
-}
+ sem_init(&g_sim_signal_start,0,0);
+ sem_init(&g_sim_signal_finish,0,0);
+ pthread_create(&g_simulation_thread,NULL,gpgpu_sim_thread,NULL);
+
+ return &g_the_gpu;
+}
-static void print_simulation_time()
+void print_simulation_time()
{
time_t current_time, difference, d, h, m, s;
current_time = time((time_t *)NULL);
@@ -130,29 +159,31 @@ static void print_simulation_time()
int gpgpu_cuda_ptx_sim_main_perf( const char *kernel_key,
struct dim3 gridDim,
struct dim3 blockDim,
- struct gpgpu_ptx_sim_arg *grid_params )
+ gpgpu_ptx_sim_arg_list_t grid_params )
{
- gpgpu_cuda_ptx_sim_init_grid(kernel_key,grid_params,gridDim,blockDim);
- run_gpu_sim(sg_grid_num++);
- print_simulation_time();
+ kernel_info_t grid = gpgpu_cuda_ptx_sim_init_grid(kernel_key,grid_params,gridDim,blockDim);
+ g_the_gpu.launch(grid);
+ sem_post(&g_sim_signal_start);
+ sem_wait(&g_sim_signal_finish);
return 0;
}
int gpgpu_opencl_ptx_sim_main_perf( class function_info *entry,
struct dim3 gridDim,
struct dim3 blockDim,
- struct gpgpu_ptx_sim_arg *grid_params )
+ gpgpu_ptx_sim_arg_list_t grid_params )
{
- gpgpu_opencl_ptx_sim_init_grid(entry,grid_params,gridDim,blockDim);
- run_gpu_sim(sg_grid_num++);
- print_simulation_time();
+ kernel_info_t grid = gpgpu_opencl_ptx_sim_init_grid(entry,grid_params,gridDim,blockDim);
+ g_the_gpu.launch(grid);
+ sem_post(&g_sim_signal_start);
+ sem_wait(&g_sim_signal_finish);
return 0;
}
int gpgpu_opencl_ptx_sim_main_func( class function_info *entry,
struct dim3 gridDim,
struct dim3 blockDim,
- struct gpgpu_ptx_sim_arg *grid_params )
+ gpgpu_ptx_sim_arg_list_t grid_params )
{
printf("GPGPU-Sim PTX API: OpenCL functional-only simulation not yet implemented (use performance simulation)\n");
exit(1);
diff --git a/src/gpgpusim_entrypoint.h b/src/gpgpusim_entrypoint.h
index 2563c5e..22b82f2 100644
--- a/src/gpgpusim_entrypoint.h
+++ b/src/gpgpusim_entrypoint.h
@@ -70,20 +70,20 @@
#include <time.h>
extern time_t g_simulation_starttime;
-void gpgpu_ptx_sim_init_perf();
+class gpgpu_sim *gpgpu_ptx_sim_init_perf();
int gpgpu_cuda_ptx_sim_main_perf( const char *kernel_key,
struct dim3 gridDim,
struct dim3 blockDim,
- struct gpgpu_ptx_sim_arg *grid_params );
+ gpgpu_ptx_sim_arg_list_t grid_params );
int gpgpu_opencl_ptx_sim_main_perf( class function_info *entry,
struct dim3 gridDim,
struct dim3 blockDim,
- struct gpgpu_ptx_sim_arg *grid_params );
+ gpgpu_ptx_sim_arg_list_t grid_params );
int gpgpu_opencl_ptx_sim_main_func( class function_info *entry,
struct dim3 gridDim,
struct dim3 blockDim,
- struct gpgpu_ptx_sim_arg *grid_params );
+ gpgpu_ptx_sim_arg_list_t grid_params );
#endif
diff --git a/src/intersim/Makefile b/src/intersim/Makefile
index 41525fd..c4f4702 100644
--- a/src/intersim/Makefile
+++ b/src/intersim/Makefile
@@ -20,7 +20,7 @@ CPPFLAGS = -g -Wall
ifneq ($(DEBUG),1)
CPPFLAGS = -O3 -g
else
-CPPFLAGS += -D_GLIBCXX_DEBUG -DGLIBCXX_DEBUG_PEDANTIC
+CPPFLAGS +=
endif
TEST = -DUNIT_TEST
diff --git a/src/intersim/interconnect_interface.cpp b/src/intersim/interconnect_interface.cpp
index 737e61e..b94e065 100644
--- a/src/intersim/interconnect_interface.cpp
+++ b/src/intersim/interconnect_interface.cpp
@@ -82,7 +82,7 @@ class mycomparison {
public:
bool operator() (const void* lhs, const void* rhs) const
{
- return( ((mem_fetch_t *)lhs)->icnt_receive_time > ((mem_fetch_t *) rhs)->icnt_receive_time);
+ return( ((mem_fetch *)lhs)->icnt_receive_time > ((mem_fetch *) rhs)->icnt_receive_time);
}
};
@@ -95,7 +95,7 @@ priority_queue<void * , vector<void* >, mycomparison> * out_buf_fixedlat_buf;
//perfect icnt stats:
unsigned int* max_fixedlat_buf_size;
-static unsigned int net_c; //number of inetrconnection networks
+static unsigned int net_c; //number of interconnection networks
static unsigned int _n_shader = 0;
static unsigned int _n_mem = 0;
@@ -287,24 +287,16 @@ void icnt_init_grid (){
}
}
-int interconnect_has_buffer(unsigned int input_node,
- unsigned int *size)
+int interconnect_has_buffer(unsigned int input_node, unsigned int tot_req_size)
{
unsigned int input = node_map[input_node];
int has_buffer;
- int tot_req_size = 0;
- for (unsigned int i=0; i<(_n_mem+_n_shader);i++ ) {
- if (size[i]) {
- tot_req_size+= size[i];
- }
- }
unsigned int n_flits = tot_req_size / _flit_size + ((tot_req_size % _flit_size)? 1:0);
if (!(fixed_lat_icnt || perfect_icnt)) {
has_buffer = (traffic[0]->_partial_packets[input][0].size() + n_flits) <= input_buffer_capacity;
- if ((net_c>1) && is_mem(input)) {
+ if ((net_c>1) && is_mem(input))
has_buffer = (traffic[1]->_partial_packets[input][0].size() + n_flits) <= input_buffer_capacity;
- }
} else {
has_buffer = 1;
}
@@ -322,7 +314,7 @@ void interconnect_push ( unsigned int input_node, unsigned int output_node,
#endif
if (fixed_lat_icnt) {
- ((mem_fetch_t *) data)->icnt_receive_time = gpu_sim_cycle + fixed_latency(input,output);
+ ((mem_fetch *) data)->icnt_receive_time = gpu_sim_cycle + fixed_latency(input,output);
out_buf_fixedlat_buf[output].push(data); //deliver the whole packet to destination in zero cycles
if (out_buf_fixedlat_buf[output].size() > max_fixedlat_buf_size[output]) {
max_fixedlat_buf_size[output]= out_buf_fixedlat_buf[output].size();
@@ -356,10 +348,10 @@ void* interconnect_pop(unsigned int output_node)
void* data = NULL;
if (fixed_lat_icnt) {
if (!out_buf_fixedlat_buf[output].empty()) {
- if (((mem_fetch_t *)out_buf_fixedlat_buf[output].top())->icnt_receive_time <= gpu_sim_cycle) {
+ if (((mem_fetch *)out_buf_fixedlat_buf[output].top())->icnt_receive_time <= gpu_sim_cycle) {
data = out_buf_fixedlat_buf[output].top();
out_buf_fixedlat_buf[output].pop();
- assert (((mem_fetch_t *)data)->icnt_receive_time);
+ assert (((mem_fetch *)data)->icnt_receive_time);
}
}
} else {
@@ -386,7 +378,9 @@ extern int DISPLAY_PAIR_LATENCY ;
void init_interconnect (char* config_file,
- unsigned int n_shader, unsigned int n_mem)
+ unsigned int n_shader,
+ unsigned int n_mem,
+ struct shader_core_config *shader_config )
{
_n_shader = n_shader;
_n_mem = n_mem;
@@ -457,15 +451,15 @@ void init_interconnect (char* config_file,
if (icnt_config.GetInt("input_buf_size")) {
input_buffer_capacity = icnt_config.GetInt("input_buf_size");
} else {
- if (gpgpu_cache_dl1_opt && !gpgpu_no_dl1) {
+ if (shader_config->gpgpu_cache_dl1_opt && !shader_config->gpgpu_no_dl1) {
int l1cache_linesize = 32;
- sscanf(gpgpu_cache_dl1_opt,"%*d:%d:%*d:%*c", &l1cache_linesize);
- input_buffer_capacity = gpu_n_thread_per_shader*(l1cache_linesize/_flit_size+(int)ceil(8.0f/_flit_size));
+ sscanf(shader_config->gpgpu_cache_dl1_opt,"%*d:%d:%*d:%*c", &l1cache_linesize);
+ input_buffer_capacity = shader_config->n_thread_per_shader*(l1cache_linesize/_flit_size+(int)ceil(8.0f/_flit_size));
} else {
- input_buffer_capacity = gpu_n_thread_per_shader*((int)ceil(8.0f/_flit_size));
+ input_buffer_capacity = shader_config->n_thread_per_shader*((int)ceil(8.0f/_flit_size));
}
}
- create_buf(traffic[0]->_dests,warp_size,icnt_config.GetInt( "num_vcs" ));
+ create_buf(traffic[0]->_dests,shader_config->warp_size,icnt_config.GetInt( "num_vcs" ));
MATLAB_OUTPUT = icnt_config.GetInt("MATLAB_OUTPUT");
DISPLAY_LAT_DIST = icnt_config.GetInt("DISPLAY_LAT_DIST");
DISPLAY_HOP_DIST = icnt_config.GetInt("DISPLAY_HOP_DIST");
@@ -557,14 +551,18 @@ void transfer2boundary_buf(int output) {
}
void time_vector_update(unsigned int uid, int slot , long int cycle, int type);
-void time_vector_update_icnt_injected(void* data, int input) {
- mem_fetch_t* mf = (mem_fetch_t*) data;
- unsigned int uid = mf->write? mf->request_uid : mf->mshr->insts[0].uid;
- long int cycle = gpu_sim_cycle + gpu_tot_sim_cycle;
- int req_type = mf->write? WT_REQ : RD_REQ;
- if (is_mem(input)) {
- time_vector_update( uid, MR_2SH_ICNT_INJECTED, cycle, req_type );
- } else {
- time_vector_update( uid, MR_ICNT_INJECTED, cycle,req_type );
+
+void time_vector_update_icnt_injected(void* data, int input)
+{
+ mem_fetch* mf = (mem_fetch*) data;
+ if( mf->mshr && !mf->mshr->isinst() ) {
+ unsigned uid=mf->m_write? mf->request_uid : mf->mshr->get_insts_uid();
+ long int cycle = gpu_sim_cycle + gpu_tot_sim_cycle;
+ int req_type = mf->m_write? WT_REQ : RD_REQ;
+ if (is_mem(input)) {
+ time_vector_update( uid, MR_2SH_ICNT_INJECTED, cycle, req_type );
+ } else {
+ time_vector_update( uid, MR_ICNT_INJECTED, cycle,req_type );
+ }
}
}
diff --git a/src/intersim/interconnect_interface.h b/src/intersim/interconnect_interface.h
index 541f992..3e3826d 100644
--- a/src/intersim/interconnect_interface.h
+++ b/src/intersim/interconnect_interface.h
@@ -13,12 +13,14 @@ struct glue_buf {
};
//node side functions
-int interconnect_has_buffer(unsigned int input, unsigned int *size);
+int interconnect_has_buffer(unsigned int input, unsigned int size);
void interconnect_push ( unsigned int input, unsigned int output,
void* data, unsigned int size);
void* interconnect_pop(unsigned int output);
-void init_interconnect (char* config_file,
- unsigned int n_shader, unsigned int n_mem);
+void init_interconnect (char* config_file,
+ unsigned int n_shader,
+ unsigned int n_mem,
+ struct shader_core_config *shader_config);
void advance_interconnect();
unsigned interconnect_busy();
void interconnect_stats() ;
@@ -30,6 +32,10 @@ void write_out_buf(int output, Flit * data);
void transfer2boundary_buf(int output);
void time_vector_update_icnt_injected(void* mf, int input);
+// other
+void icnt_overal_stat();
+void icnt_init_grid ();
+
#endif
diff --git a/src/intersim/statwraper.cpp b/src/intersim/statwraper.cpp
index 9590f6f..c709dc0 100644
--- a/src/intersim/statwraper.cpp
+++ b/src/intersim/statwraper.cpp
@@ -2,10 +2,10 @@
#include "stats.hpp"
#include <stdio.h>
-void* StatCreate (const char * name, double bin_size, int num_bins) {
+Stats* StatCreate (const char * name, double bin_size, int num_bins) {
Stats* newstat = new Stats(NULL,name,bin_size,num_bins);
newstat->Clear ();
- return(void *) newstat;
+ return newstat;
}
void StatClear(void * st)
@@ -45,11 +45,6 @@ void StatDisp (void * st)
}
}
-void StatDumptofile (void * st, FILE *f)
-{
-
-}
-
#if 0
int main ()
{
diff --git a/src/intersim/statwraper.h b/src/intersim/statwraper.h
index 35ca6de..65c2ab9 100644
--- a/src/intersim/statwraper.h
+++ b/src/intersim/statwraper.h
@@ -1,13 +1,12 @@
#ifndef STAT_WRAPER_H
#define STAT_WRAPER_H
-void* StatCreate (const char * name, double bin_size, int num_bins) ;
+class Stats* StatCreate (const char * name, double bin_size, int num_bins) ;
void StatClear(void * st);
void StatAddSample (void * st, int val);
double StatAverage(void * st) ;
double StatMax(void * st) ;
double StatMin(void * st) ;
void StatDisp (void * st);
-void StatDumptofile (void * st, FILE f);
#endif