diff options
| author | Tor Aamodt <[email protected]> | 2010-10-18 02:43:17 -0800 |
|---|---|---|
| committer | Tor Aamodt <[email protected]> | 2010-10-18 02:43:17 -0800 |
| commit | 87e4da5fc6086c3d0a661af1929255a8cbd728d7 (patch) | |
| tree | a4f40e66f5ca0d6efdf9d51672a1180c8a381170 /src | |
| parent | b577cbcdf229a2c02d1bf8584c6e82be7a14cb33 (diff) | |
Re-designed cache model:
- read only cache model with integrated mshrs (no L1D, yet); new
cache interface should be easily extendable to support texture
cache with latency fifo and separate tag/data arrays, though
this is not yet added (currently tags and data arrays are not
decoupled for texture)
- new partition model using the above
removes all old MSHRs, L1D etc...
passing CUDA 3.1 regression
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 7875]
Diffstat (limited to 'src')
26 files changed, 1423 insertions, 2317 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index 2134cfc..507e02f 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -29,12 +29,6 @@ unsigned core_config::shmem_bank_func(address_type addr, unsigned) const return ((addr/WORD_SIZE) % gpgpu_n_shmem_bank); } -unsigned core_config::dcache_bank_func(address_type add, unsigned line_size) const -{ - if (gpgpu_no_dl1) return 1; //no banks - else return (add / line_size) & (gpgpu_n_cache_bank - 1); -} - address_type null_tag_func(address_type address, unsigned line_size) { return address; //no modification: each address is its own tag. @@ -101,20 +95,18 @@ void warp_inst_t::get_memory_access_list() case global_space: case local_space: case param_space_local: global_mem_access=true; warp_parts = 1; - line_size = m_config->gpgpu_cache_dl1_linesize; + line_size = 0; if( m_config->gpgpu_coalesce_arch == 13 ){ warp_parts = 2; - if( m_config->gpgpu_no_dl1 ) { - // line size is dependant on instruction; - 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); - } + // line size is dependant on instruction; + 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); } - } - bank_func = &core_config::dcache_bank_func; + } else abort(); + bank_func = &core_config::null_bank_func; tag_func = line_size_based_tag_func; limit_broadcast = false; break; @@ -178,7 +170,7 @@ void warp_inst_t::get_memory_access_list() // 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 = 0; i < get_accessq_size(); i++) { - if (m_config->gpgpu_coalesce_arch == 13 && m_config->gpgpu_no_dl1) { + if (m_config->gpgpu_coalesce_arch == 13) { // do coalescing here. char* quarter_counts = accessq(i).quarter_count; bool low = quarter_counts[0] or quarter_counts[1]; diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index ed832b6..fc2f0d4 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -1,6 +1,24 @@ #ifndef ABSTRACT_HARDWARE_MODEL_INCLUDED #define ABSTRACT_HARDWARE_MODEL_INCLUDED +enum _memory_space_t { + undefined_space=0, + reg_space, + local_space, + shared_space, + param_space_unclassified, + param_space_kernel, /* global to all threads in a kernel : read-only */ + param_space_local, /* local to a thread : read-writable */ + const_space, + tex_space, + surf_space, + global_space, + generic_space, + instruction_space +}; + +#ifdef __cplusplus + #include <string.h> #include <stdio.h> @@ -23,30 +41,12 @@ enum uarch_op_t { }; typedef enum uarch_op_t op_type; -enum _memory_space_t { - undefined_space=0, - reg_space, - local_space, - shared_space, - param_space_unclassified, - param_space_kernel, /* global to all threads in a kernel : read-only */ - param_space_local, /* local to a thread : read-writable */ - const_space, - tex_space, - surf_space, - global_space, - generic_space, - instruction_space -}; - enum _memory_op_t { no_memory_op = 0, memory_load, memory_store }; -#ifdef __cplusplus - #include <bitset> #include <list> #include <vector> @@ -60,6 +60,29 @@ struct dim3 { }; #endif +#if 0 + +// detect gcc 4.3 and use unordered map (part of c++0x) +// unordered map doesn't play nice with _GLIBCXX_DEBUG, just use a map if its enabled. +#if defined( __GNUC__ ) and not defined( _GLIBCXX_DEBUG ) +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 + #include <unordered_map> + #define my_hash_map std::unordered_map +#else + #include <ext/hash_map> + namespace std { + using namespace __gnu_cxx; + } + #define my_hash_map std::hash_map +#endif +#else + #include <map> + #define my_hash_map std::map + #define USE_MAP +#endif + +#endif + void increment_x_then_y_then_z( dim3 &i, const dim3 &bound); class kernel_info_t { @@ -139,18 +162,14 @@ struct core_config { // memory request architecture parameters int gpgpu_coalesce_arch; - bool gpgpu_no_dl1; int gpgpu_shmem_pipe_speedup; unsigned gpgpu_cache_texl1_linesize; unsigned gpgpu_cache_constl1_linesize; - unsigned gpgpu_cache_dl1_linesize; static const address_type WORD_SIZE=4; unsigned null_bank_func(address_type, unsigned) const { return 1; } int gpgpu_n_shmem_bank; unsigned shmem_bank_func(address_type addr, unsigned) const; - int gpgpu_n_cache_bank; - unsigned dcache_bank_func(address_type add, unsigned line_size) const; }; class core_t { @@ -363,7 +382,6 @@ private: recheck_cache = false; need_wb = false; wb_addr = 0; - reserved_mshr = NULL; } public: @@ -382,12 +400,19 @@ public: bool recheck_cache; bool need_wb; address_type wb_addr; // writeback address (if necessary). - class mshr_entry* reserved_mshr; private: static unsigned next_access_uid; }; +class mem_fetch; + +class mem_fetch_interface { +public: + virtual bool full( unsigned size, bool write ) const = 0; + virtual void push( mem_fetch *mf ) = 0; +}; + #define MAX_REG_OPERANDS 8 struct dram_callback_t { @@ -634,4 +659,5 @@ void move_warp( warp_inst_t *&dst, warp_inst_t *&src ); 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/Makefile b/src/cuda-sim/Makefile index 39a6641..0b1a793 100644 --- a/src/cuda-sim/Makefile +++ b/src/cuda-sim/Makefile @@ -169,6 +169,199 @@ cuda_device_printf.o: ptx.tab.c ptx_ir.o: ptx.tab.c ptx_parser_decode.def ptx_loader.o: ptx.tab.c ptx_parser_decode.def ptx_parser.o: ptx.tab.c ptx_parser_decode.def +ptxinfo.tab.o: ptx.tab.c +ptx-stats.o: ptx.tab.c +ptx_sim.o: ptx.tab.c +cuda-sim.o: ptx.tab.c +lex.ptxinfo_.o: ptx.tab.c +lex.ptx_.o: ptx.tab.c # DO NOT DELETE +cuda_device_printf.o: cuda_device_printf.h ptx_ir.h +cuda_device_printf.o: ../abstract_hardware_model.h /usr/include/assert.h +cuda_device_printf.o: /usr/include/features.h /usr/include/sys/cdefs.h +cuda_device_printf.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +cuda_device_printf.o: /usr/include/gnu/stubs-64.h ptx_sim.h +cuda_device_printf.o: /usr/include/stdlib.h /usr/include/sys/types.h +cuda_device_printf.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +cuda_device_printf.o: /usr/include/time.h /usr/include/endian.h +cuda_device_printf.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h +cuda_device_printf.o: /usr/include/sys/select.h /usr/include/bits/select.h +cuda_device_printf.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +cuda_device_printf.o: /usr/include/sys/sysmacros.h +cuda_device_printf.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h +cuda_device_printf.o: dram_callback.h ../tr1_hash_map.h opcodes.h opcodes.def +cuda_device_printf.o: memory.h /usr/include/string.h /usr/include/stdio.h +cuda_device_printf.o: /usr/include/libio.h /usr/include/_G_config.h +cuda_device_printf.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h +cuda_device_printf.o: /usr/include/bits/sys_errlist.h ../option_parser.h +cuda-sim.o: cuda-sim.h ../abstract_hardware_model.h dram_callback.h +cuda-sim.o: /usr/include/stdlib.h /usr/include/features.h +cuda-sim.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +cuda-sim.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h +cuda-sim.o: /usr/include/sys/types.h /usr/include/bits/types.h +cuda-sim.o: /usr/include/bits/typesizes.h /usr/include/time.h +cuda-sim.o: /usr/include/endian.h /usr/include/bits/endian.h +cuda-sim.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h +cuda-sim.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +cuda-sim.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +cuda-sim.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h ptx_ir.h +cuda-sim.o: /usr/include/assert.h ptx_sim.h ../tr1_hash_map.h opcodes.h +cuda-sim.o: opcodes.def memory.h /usr/include/string.h /usr/include/stdio.h +cuda-sim.o: /usr/include/libio.h /usr/include/_G_config.h +cuda-sim.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h +cuda-sim.o: /usr/include/bits/sys_errlist.h ../option_parser.h +cuda-sim.o: ../intersim/statwraper.h ptx-stats.h ptx_loader.h ptx_parser.h +cuda-sim.o: ../gpgpu-sim/gpu-sim.h ../gpgpu-sim/addrdec.h +cuda-sim.o: ../gpgpu-sim/shader.h /usr/include/math.h +cuda-sim.o: /usr/include/bits/huge_val.h /usr/include/bits/mathdef.h +cuda-sim.o: /usr/include/bits/mathcalls.h ../cuda-sim/dram_callback.h +cuda-sim.o: ../gpgpu-sim/delayqueue.h ../gpgpu-sim/gpu-misc.h +cuda-sim.o: ../gpgpu-sim/stack.h ../gpgpu-sim/dram.h /usr/include/zlib.h +cuda-sim.o: /usr/include/zconf.h /usr/include/unistd.h +cuda-sim.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h +cuda-sim.o: /usr/include/getopt.h ../gpgpu-sim/scoreboard.h +cuda-sim.o: ../gpgpu-sim/mem_fetch.h ../gpgpu-sim/stats.h +cuda-sim.o: ../gpgpu-sim/gpu-cache.h ../gpgpusim_entrypoint.h +cuda-sim.o: ../abstract_hardware_model.h +cuda-sim.o: decuda_pred_table/decuda_pred_table.h +instructions.o: ptx_ir.h ../abstract_hardware_model.h /usr/include/assert.h +instructions.o: /usr/include/features.h /usr/include/sys/cdefs.h +instructions.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +instructions.o: /usr/include/gnu/stubs-64.h ptx_sim.h /usr/include/stdlib.h +instructions.o: /usr/include/sys/types.h /usr/include/bits/types.h +instructions.o: /usr/include/bits/typesizes.h /usr/include/time.h +instructions.o: /usr/include/endian.h /usr/include/bits/endian.h +instructions.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h +instructions.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +instructions.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +instructions.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h +instructions.o: dram_callback.h ../tr1_hash_map.h opcodes.h opcodes.def +instructions.o: memory.h /usr/include/string.h /usr/include/stdio.h +instructions.o: /usr/include/libio.h /usr/include/_G_config.h +instructions.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h +instructions.o: /usr/include/bits/sys_errlist.h ../option_parser.h +instructions.o: /usr/include/math.h /usr/include/bits/huge_val.h +instructions.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h +instructions.o: /usr/include/fenv.h /usr/include/bits/fenv.h cuda-math.h +instructions.o: ptx_loader.h cuda_device_printf.h ../gpgpu-sim/gpu-sim.h +instructions.o: ../gpgpu-sim/addrdec.h ../gpgpu-sim/shader.h +instructions.o: ../cuda-sim/dram_callback.h ../gpgpu-sim/delayqueue.h +instructions.o: ../intersim/statwraper.h ../gpgpu-sim/gpu-misc.h +instructions.o: ../gpgpu-sim/stack.h ../gpgpu-sim/dram.h /usr/include/zlib.h +instructions.o: /usr/include/zconf.h /usr/include/unistd.h +instructions.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h +instructions.o: /usr/include/getopt.h ../gpgpu-sim/scoreboard.h +instructions.o: ../gpgpu-sim/mem_fetch.h ../gpgpu-sim/stats.h +instructions.o: ../gpgpu-sim/gpu-cache.h ../gpgpu-sim/shader.h +memory.o: memory.h ../abstract_hardware_model.h /usr/include/assert.h +memory.o: /usr/include/features.h /usr/include/sys/cdefs.h +memory.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +memory.o: /usr/include/gnu/stubs-64.h /usr/include/string.h +memory.o: /usr/include/stdio.h /usr/include/bits/types.h +memory.o: /usr/include/bits/typesizes.h /usr/include/libio.h +memory.o: /usr/include/_G_config.h /usr/include/wchar.h +memory.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h +memory.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h +memory.o: /usr/include/endian.h /usr/include/bits/endian.h +memory.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h +memory.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +memory.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +memory.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h ../debug.h +memory.o: ../abstract_hardware_model.h +ptx_ir.o: ptx_parser.h ../abstract_hardware_model.h ptx_ir.h +ptx_ir.o: /usr/include/assert.h /usr/include/features.h +ptx_ir.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +ptx_ir.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h ptx_sim.h +ptx_ir.o: /usr/include/stdlib.h /usr/include/sys/types.h +ptx_ir.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +ptx_ir.o: /usr/include/time.h /usr/include/endian.h +ptx_ir.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h +ptx_ir.o: /usr/include/sys/select.h /usr/include/bits/select.h +ptx_ir.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +ptx_ir.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +ptx_ir.o: /usr/include/alloca.h dram_callback.h ../tr1_hash_map.h opcodes.h +ptx_ir.o: opcodes.def memory.h /usr/include/string.h /usr/include/stdio.h +ptx_ir.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h +ptx_ir.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h +ptx_ir.o: ../option_parser.h cuda-sim.h +ptx_loader.o: ptx_loader.h ptx_ir.h ../abstract_hardware_model.h +ptx_loader.o: /usr/include/assert.h /usr/include/features.h +ptx_loader.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +ptx_loader.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h ptx_sim.h +ptx_loader.o: /usr/include/stdlib.h /usr/include/sys/types.h +ptx_loader.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +ptx_loader.o: /usr/include/time.h /usr/include/endian.h +ptx_loader.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h +ptx_loader.o: /usr/include/sys/select.h /usr/include/bits/select.h +ptx_loader.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +ptx_loader.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +ptx_loader.o: /usr/include/alloca.h dram_callback.h ../tr1_hash_map.h +ptx_loader.o: opcodes.h opcodes.def memory.h /usr/include/string.h +ptx_loader.o: /usr/include/stdio.h /usr/include/libio.h +ptx_loader.o: /usr/include/_G_config.h /usr/include/wchar.h +ptx_loader.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h +ptx_loader.o: ../option_parser.h cuda-sim.h ptx_parser.h +ptx_loader.o: /usr/include/dirent.h /usr/include/bits/dirent.h +ptx_loader.o: /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h +ptx_loader.o: /usr/include/linux/limits.h +ptx_parser.o: ptx_parser.h ../abstract_hardware_model.h ptx_ir.h +ptx_parser.o: /usr/include/assert.h /usr/include/features.h +ptx_parser.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +ptx_parser.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h ptx_sim.h +ptx_parser.o: /usr/include/stdlib.h /usr/include/sys/types.h +ptx_parser.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +ptx_parser.o: /usr/include/time.h /usr/include/endian.h +ptx_parser.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h +ptx_parser.o: /usr/include/sys/select.h /usr/include/bits/select.h +ptx_parser.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +ptx_parser.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +ptx_parser.o: /usr/include/alloca.h dram_callback.h ../tr1_hash_map.h +ptx_parser.o: opcodes.h opcodes.def memory.h /usr/include/string.h +ptx_parser.o: /usr/include/stdio.h /usr/include/libio.h +ptx_parser.o: /usr/include/_G_config.h /usr/include/wchar.h +ptx_parser.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h +ptx_parser.o: ../option_parser.h +ptx_sim.o: ptx_sim.h /usr/include/stdlib.h /usr/include/features.h +ptx_sim.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +ptx_sim.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h +ptx_sim.o: /usr/include/sys/types.h /usr/include/bits/types.h +ptx_sim.o: /usr/include/bits/typesizes.h /usr/include/time.h +ptx_sim.o: /usr/include/endian.h /usr/include/bits/endian.h +ptx_sim.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h +ptx_sim.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +ptx_sim.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +ptx_sim.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h +ptx_sim.o: dram_callback.h ../abstract_hardware_model.h ../tr1_hash_map.h +ptx_sim.o: /usr/include/assert.h opcodes.h opcodes.def memory.h +ptx_sim.o: /usr/include/string.h /usr/include/stdio.h /usr/include/libio.h +ptx_sim.o: /usr/include/_G_config.h /usr/include/wchar.h +ptx_sim.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h +ptx_sim.o: ptx_ir.h ../option_parser.h ../gpgpu-sim/gpu-sim.h +ptx_sim.o: ../gpgpu-sim/addrdec.h ../gpgpu-sim/shader.h /usr/include/math.h +ptx_sim.o: /usr/include/bits/huge_val.h /usr/include/bits/mathdef.h +ptx_sim.o: /usr/include/bits/mathcalls.h ../cuda-sim/dram_callback.h +ptx_sim.o: ../gpgpu-sim/delayqueue.h ../intersim/statwraper.h +ptx_sim.o: ../gpgpu-sim/gpu-misc.h ../gpgpu-sim/stack.h ../gpgpu-sim/dram.h +ptx_sim.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h +ptx_sim.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h +ptx_sim.o: /usr/include/getopt.h ../gpgpu-sim/scoreboard.h +ptx_sim.o: ../gpgpu-sim/mem_fetch.h ../gpgpu-sim/stats.h +ptx_sim.o: ../gpgpu-sim/gpu-cache.h ../gpgpu-sim/shader.h +ptx-stats.o: ptx_ir.h ../abstract_hardware_model.h /usr/include/assert.h +ptx-stats.o: /usr/include/features.h /usr/include/sys/cdefs.h +ptx-stats.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +ptx-stats.o: /usr/include/gnu/stubs-64.h ptx_sim.h /usr/include/stdlib.h +ptx-stats.o: /usr/include/sys/types.h /usr/include/bits/types.h +ptx-stats.o: /usr/include/bits/typesizes.h /usr/include/time.h +ptx-stats.o: /usr/include/endian.h /usr/include/bits/endian.h +ptx-stats.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h +ptx-stats.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +ptx-stats.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +ptx-stats.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h +ptx-stats.o: dram_callback.h ../tr1_hash_map.h opcodes.h opcodes.def memory.h +ptx-stats.o: /usr/include/string.h /usr/include/stdio.h /usr/include/libio.h +ptx-stats.o: /usr/include/_G_config.h /usr/include/wchar.h +ptx-stats.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h +ptx-stats.o: ../option_parser.h ptx-stats.h diff --git a/src/gpgpu-sim/delayqueue.h b/src/gpgpu-sim/delayqueue.h index 050a916..cb5ded0 100644 --- a/src/gpgpu-sim/delayqueue.h +++ b/src/gpgpu-sim/delayqueue.h @@ -77,14 +77,14 @@ template <class T> struct fifo_data { T *m_data; fifo_data *m_next; - unsigned long long push_time; //for stat collection }; template <class T> class fifo_pipeline { public: - fifo_pipeline(const char* nm, unsigned int minlen, unsigned int maxlen, unsigned long long current_time ) + fifo_pipeline(const char* nm, unsigned int minlen, unsigned int maxlen ) { + assert(maxlen); m_name = nm; m_min_len = minlen; m_max_len = maxlen; @@ -93,8 +93,7 @@ public: 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); + push(NULL); } ~fifo_pipeline() @@ -106,9 +105,9 @@ public: } } - void push(T* data, unsigned long long current_time ) + void push(T* data ) { - if (m_max_len) assert(m_length < 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>(); @@ -123,17 +122,15 @@ public: } m_tail->m_next = NULL; m_tail->m_data = data; - m_tail->push_time = current_time; } - T* pop( unsigned long long current_time ) + T* pop() { 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; @@ -147,7 +144,7 @@ public: } m_n_element--; if (m_min_len && m_length < m_min_len) { - push(NULL,current_time); + push(NULL); m_n_element--; // uncount NULL elements inserted to create delays } } else { @@ -165,14 +162,14 @@ public: } } - void set_min_length(unsigned int new_min_len, unsigned long long current_time) + void set_min_length(unsigned int new_min_len) { 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); + push(NULL); m_n_element--; // uncount NULL elements inserted to create delays } } else { @@ -188,7 +185,7 @@ public: if (!iter) { // there is only one node, and that node is empty assert(m_head->m_data == 0); - pop(current_time); + pop(); } else { // there are more than one node, and tail node is empty assert(iter->m_next == m_tail); @@ -206,7 +203,6 @@ public: 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; } void print() const { @@ -229,8 +225,6 @@ private: 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 9f79c7e..a1187ec 100644 --- a/src/gpgpu-sim/dram.cc +++ b/src/gpgpu-sim/dram.cc @@ -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 @@ -69,6 +69,7 @@ #include "dram.h" #include "mem_latency_stat.h" #include "dram_sched.h" +#include "mem_fetch.h" #ifdef DRAM_VERIFY int PRINT_CYCLE = 0; @@ -98,12 +99,12 @@ dram_t::dram_t( unsigned int partition_id, const struct memory_config *config, m bk[i]->state = BANK_IDLE; prio = 0; - rwq = new fifo_pipeline<dram_req_t>("rwq",m_config->CL,m_config->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); + rwq = new fifo_pipeline<dram_req_t>("rwq",m_config->CL,m_config->CL+1); + mrqq = new fifo_pipeline<dram_req_t>("mrqq",0,2); + returnq = new fifo_pipeline<mem_fetch>("dramreturnq",0,m_config->gpgpu_dram_sched_queue_size); m_fast_ideal_scheduler = NULL; - if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) - m_fast_ideal_scheduler = new ideal_dram_scheduler(m_config,this,stats); + if ( m_config->scheduler_type == DRAM_FRFCFS ) + m_fast_ideal_scheduler = new frfcfs_scheduler(m_config,this,stats); n_cmd = 0; n_activity = 0; n_nop = 0; @@ -137,24 +138,20 @@ dram_t::dram_t( unsigned int partition_id, const struct memory_config *config, m mrqq_Dist = StatCreate("mrqq_length",1,64); //track up to 64 entries } -int dram_t::full() +bool dram_t::full() const { - int full = 0; - 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 = (mrqq->get_length() >= m_config->gpgpu_dram_sched_queue_size); - } - - return full; + if( m_config->gpgpu_dram_sched_queue_size == 0 ) + return false; + if( m_config->scheduler_type == DRAM_FRFCFS ) + return m_fast_ideal_scheduler->num_pending() >= m_config->gpgpu_dram_sched_queue_size; + else + return mrqq->full(); } -unsigned int dram_t::que_length() const +unsigned dram_t::que_length() const { unsigned nreqs = 0; - if (m_config->scheduler_type == DRAM_IDEAL_FAST ) { + if (m_config->scheduler_type == DRAM_FRFCFS ) { nreqs = m_fast_ideal_scheduler->num_pending(); } else { nreqs = mrqq->get_length(); @@ -195,12 +192,13 @@ dram_req_t::dram_req_t( class mem_fetch *mf ) void dram_t::push( class mem_fetch *data ) { dram_req_t *mrq = new dram_req_t(data); - mrqq->push(mrq,gpu_sim_cycle); + data->set_status(IN_PARTITION_MC_INTERFACE_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + mrqq->push(mrq); // stats... n_req += 1; n_req_partial += 1; - if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) { + if ( m_config->scheduler_type == DRAM_FRFCFS ) { unsigned nreqs = m_fast_ideal_scheduler->num_pending(); if ( nreqs > max_mrqs_temp) max_mrqs_temp = nreqs; @@ -215,10 +213,10 @@ void dram_t::scheduler_fifo() if (!mrqq->empty()) { unsigned int bkn; dram_req_t *head_mrqq = mrqq->top(); + head_mrqq->data->set_status(IN_PARTITION_MC_BANK_ARB_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); bkn = head_mrqq->bk; - if (!bk[bkn]->mrq) { - bk[bkn]->mrq = mrqq->pop(gpu_sim_cycle); - } + if (!bk[bkn]->mrq) + bk[bkn]->mrq = mrqq->pop(); } } @@ -226,23 +224,40 @@ void dram_t::scheduler_fifo() #define DEC2ZERO(x) x = (x)? (x-1) : 0; #define SWAP(a,b) a ^= b; b ^= a; a ^= b; -void dram_t::issueCMD() +void dram_t::cycle() { - unsigned i,j,k; - unsigned char issued; - issued = 0; + + if( !returnq->full() ) { + dram_req_t *cmd = rwq->pop(); + if( cmd ) { +#ifdef DRAM_VIEWCMD + printf("\tDQ: BK%d Row:%03x Col:%03x", cmd->bk, cmd->row, cmd->col + cmd->dqbytes); +#endif + cmd->dqbytes += m_config->BL * m_config->busW * m_config->gpu_n_mem_per_ctrlr; /*16 bytes*/ + if (cmd->dqbytes >= cmd->nbytes) { + mem_fetch *data = cmd->data; + data->set_status(IN_PARTITION_MC_RETURNQ,gpu_sim_cycle+gpu_tot_sim_cycle); + data->set_type(REPLY_DATA); + returnq->push(data); + delete cmd; + } +#ifdef DRAM_VIEWCMD + printf("\n"); +#endif + } + } /* check if the upcoming request is on an idle bank */ /* Should we modify this so that multiple requests are checked? */ switch (m_config->scheduler_type) { case DRAM_FIFO: scheduler_fifo(); break; - case DRAM_IDEAL_FAST: fast_scheduler_ideal(); break; + case DRAM_FRFCFS: fast_scheduler_ideal(); break; default: printf("Error: Unknown DRAM scheduler type\n"); assert(0); } - if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) { + if ( m_config->scheduler_type == DRAM_FRFCFS ) { unsigned nreqs = m_fast_ideal_scheduler->num_pending(); if ( nreqs > max_mrqs) { max_mrqs = nreqs; @@ -256,11 +271,15 @@ void dram_t::issueCMD() ave_mrqs += mrqq->get_length(); ave_mrqs_partial += mrqq->get_length(); } - k=m_config->nbk; + + unsigned k=m_config->nbk; + bool issued = false; + // check if any bank is ready to issue a new read - for (i=0;i<m_config->nbk;i++) { - j = (i + prio) % m_config->nbk; + for (unsigned i=0;i<m_config->nbk;i++) { + unsigned j = (i + prio) % m_config->nbk; if (bk[j]->mrq) { //if currently servicing a memory request + bk[j]->mrq->data->set_status(IN_PARTITION_DRAM,gpu_sim_cycle+gpu_tot_sim_cycle); // correct row activated for a READ if ( !issued && !CCDc && !bk[j]->RCDc && (bk[j]->curr_row == bk[j]->mrq->row) && @@ -269,13 +288,13 @@ void dram_t::issueCMD() !rwq->full() ) { if (rw==WRITE) { rw=READ; - rwq->set_min_length(m_config->CL,gpu_sim_cycle); + rwq->set_min_length(m_config->CL); } - rwq->push(bk[j]->mrq,gpu_sim_cycle); + rwq->push(bk[j]->mrq); bk[j]->mrq->txbytes += m_config->BL * m_config->busW * m_config->gpu_n_mem_per_ctrlr; //16 bytes CCDc = m_config->tCCD; RTWc = m_config->tRTW; - issued = 1; + issued = true; n_rd++; bwutil+= m_config->BL/2; bwutil_partial += m_config->BL/2; @@ -299,13 +318,13 @@ void dram_t::issueCMD() !rwq->full() ) { if (rw==READ) { rw=WRITE; - rwq->set_min_length(m_config->WL,gpu_sim_cycle); + rwq->set_min_length(m_config->WL); } - rwq->push(bk[j]->mrq,gpu_sim_cycle); + rwq->push(bk[j]->mrq); bk[j]->mrq->txbytes += m_config->BL * m_config->busW * m_config->gpu_n_mem_per_ctrlr; /*16 bytes*/ CCDc = m_config->tCCD; - issued = 1; + issued = true; n_wr++; bwutil+=2; bwutil_partial += m_config->BL/2; @@ -340,7 +359,7 @@ void dram_t::issueCMD() bk[j]->RASc = m_config->tRAS; bk[j]->RCc = m_config->tRC; prio = (j + 1) % m_config->nbk; - issued = 1; + issued = true; n_act_partial++; n_act++; } @@ -355,7 +374,7 @@ void dram_t::issueCMD() bk[j]->state = BANK_IDLE; bk[j]->RPc = m_config->tRP; prio = (j + 1) % m_config->nbk; - issued = 1; + issued = true; n_pre++; n_pre_partial++; #ifdef DRAM_VERIFY @@ -388,7 +407,7 @@ void dram_t::issueCMD() DEC2ZERO(CCDc); DEC2ZERO(RTWc); DEC2ZERO(WTRc); - for (j=0;j<m_config->nbk;j++) { + for (unsigned j=0;j<m_config->nbk;j++) { DEC2ZERO(bk[j]->RCDc); DEC2ZERO(bk[j]->RASc); DEC2ZERO(bk[j]->RCc); @@ -404,44 +423,7 @@ void dram_t::issueCMD() //if mrq is being serviced by dram, gets popped after CL latency fulfilled class mem_fetch* dram_t::pop() { - class mem_fetch *data = NULL; - dram_req_t *mrq = rwq->pop(gpu_sim_cycle); - if (mrq) { -#ifdef DRAM_VIEWCMD - printf("\tDQ: BK%d Row:%03x Col:%03x", - mrq->bk, mrq->row, mrq->col + mrq->dqbytes); -#endif - mrq->dqbytes += m_config->BL * m_config->busW * m_config->gpu_n_mem_per_ctrlr; /*16 bytes*/ - if (mrq->dqbytes >= mrq->nbytes) { - if (m_config->gpgpu_memlatency_stat) { - unsigned dq_latency = gpu_sim_cycle + gpu_tot_sim_cycle - mrq->timestamp; - 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; - delete mrq; - } - } -#ifdef DRAM_VIEWCMD - printf("\n"); -#endif - 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(); + return returnq->pop(); } void dram_t::print( FILE* simFile) const @@ -501,15 +483,6 @@ void dram_t::print_stat( FILE* simFile ) max_mrqs_temp = 0; } -void dram_t::queue_latency_log_dump( FILE *fp ) -{ - 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 diff --git a/src/gpgpu-sim/dram.h b/src/gpgpu-sim/dram.h index cf9f68d..2a94a31 100644 --- a/src/gpgpu-sim/dram.h +++ b/src/gpgpu-sim/dram.h @@ -125,22 +125,18 @@ class dram_t public: dram_t( unsigned int parition_id, const struct memory_config *config, class memory_stats_t *stats ); - int full(); + bool full() const; void print( FILE* simFile ) const; void visualize() const; void print_stat( FILE* simFile ); - unsigned int que_length() const; + unsigned 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 cycle(); void dram_log (int task); struct memory_partition_unit *m_memory_partition_unit; @@ -188,7 +184,7 @@ private: unsigned int max_mrqs; unsigned int ave_mrqs; - class ideal_dram_scheduler* m_fast_ideal_scheduler; + class frfcfs_scheduler* m_fast_ideal_scheduler; unsigned int n_cmd_partial; unsigned int n_activity_partial; @@ -202,7 +198,7 @@ private: struct memory_stats_t *m_stats; class Stats* mrqq_Dist; //memory request queue inside DRAM - friend class ideal_dram_scheduler; + friend class frfcfs_scheduler; }; #endif /*DRAM_H*/ diff --git a/src/gpgpu-sim/dram_sched.cc b/src/gpgpu-sim/dram_sched.cc index 110894f..8881e8f 100644 --- a/src/gpgpu-sim/dram_sched.cc +++ b/src/gpgpu-sim/dram_sched.cc @@ -70,7 +70,7 @@ #include "../abstract_hardware_model.h" #include "mem_latency_stat.h" -ideal_dram_scheduler::ideal_dram_scheduler( const memory_config *config, dram_t *dm, memory_stats_t *stats ) +frfcfs_scheduler::frfcfs_scheduler( const memory_config *config, dram_t *dm, memory_stats_t *stats ) { m_config = config; m_stats = stats; @@ -91,20 +91,15 @@ ideal_dram_scheduler::ideal_dram_scheduler( const memory_config *config, dram_t } -void ideal_dram_scheduler::add_req( dram_req_t *req ) +void frfcfs_scheduler::add_req( dram_req_t *req ) { m_num_pending++; - m_queue[req->bk].push_front(req); std::list<dram_req_t*>::iterator ptr = m_queue[req->bk].begin(); - m_bins[req->bk][req->row].push_front( ptr ); //newest reqs to the front - - } - -inline void ideal_dram_scheduler::data_collection(unsigned int bank) +void frfcfs_scheduler::data_collection(unsigned int bank) { if (gpu_sim_cycle > row_service_timestamp[bank]) { curr_row_service_time[bank] = gpu_sim_cycle - row_service_timestamp[bank]; @@ -120,7 +115,7 @@ inline void ideal_dram_scheduler::data_collection(unsigned int bank) m_stats->num_activates[m_dram->id][bank]++; } -dram_req_t *ideal_dram_scheduler::schedule( unsigned bank, unsigned curr_row ) +dram_req_t *frfcfs_scheduler::schedule( unsigned bank, unsigned curr_row ) { int row_hit = 0; if ( m_last_row[bank] == NULL ) { @@ -164,7 +159,7 @@ dram_req_t *ideal_dram_scheduler::schedule( unsigned bank, unsigned curr_row ) } -void ideal_dram_scheduler::print( FILE *fp ) +void frfcfs_scheduler::print( FILE *fp ) { for ( unsigned b=0; b < m_config->nbk; b++ ) { printf(" %u: queue length = %u\n", b, (unsigned)m_queue[b].size() ); @@ -174,9 +169,10 @@ void ideal_dram_scheduler::print( FILE *fp ) void dram_t::fast_scheduler_ideal() { unsigned mrq_latency; - ideal_dram_scheduler *sched = m_fast_ideal_scheduler; + frfcfs_scheduler *sched = m_fast_ideal_scheduler; while ( !mrqq->empty() && (!m_config->gpgpu_dram_sched_queue_size || sched->num_pending() < m_config->gpgpu_dram_sched_queue_size)) { - dram_req_t *req = mrqq->pop(gpu_sim_cycle); + dram_req_t *req = mrqq->pop(); + req->data->set_status(IN_PARTITION_MC_INPUT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); sched->add_req(req); } @@ -189,6 +185,7 @@ void dram_t::fast_scheduler_ideal() req = sched->schedule(b, bk[b]->curr_row); if ( req ) { + req->data->set_status(IN_PARTITION_MC_BANK_ARB_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); prio = (prio+1)%m_config->nbk; bk[b]->mrq = req; if (m_config->gpgpu_memlatency_stat) { diff --git a/src/gpgpu-sim/dram_sched.h b/src/gpgpu-sim/dram_sched.h index eaad744..9f99209 100644 --- a/src/gpgpu-sim/dram_sched.h +++ b/src/gpgpu-sim/dram_sched.h @@ -74,13 +74,11 @@ #include <list> #include <map> -class ideal_dram_scheduler { +class frfcfs_scheduler { public: - ideal_dram_scheduler( const memory_config *config, dram_t *dm, memory_stats_t *stats ); + frfcfs_scheduler( const memory_config *config, dram_t *dm, memory_stats_t *stats ); void add_req( dram_req_t *req ); - std::list<dram_req_t*>::iterator binarysort_VFTF(dram_req_t *req); - std::list<dram_req_t*>::iterator sort_VFTF(dram_req_t *req); - inline void data_collection(unsigned bank); + void data_collection(unsigned bank); dram_req_t *schedule( unsigned bank, unsigned curr_row ); void print( FILE *fp ); unsigned num_pending() const { return m_num_pending;} diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index 98909ce..b26afb2 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -1,5 +1,5 @@ /* - * gpu-cache.c + * gpu-cache.cc * * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda, * George L. Yuan and the @@ -65,291 +65,163 @@ */ #include "gpu-cache.h" -#include "gpu-misc.h" -#include "addrdec.h" #include "stat-tool.h" -#include "gpu-sim.h" #include <assert.h> -#include <string.h> -cache_t::~cache_t() +tag_array::~tag_array() { delete m_lines; } -cache_t::cache_t( const char *name, const cache_config &config, int core_id, int type_id ) +tag_array::tag_array( const cache_config &config, int core_id, int type_id ) : m_config(config) { - m_name = name; - m_nset = config.nset; - m_nset_log2 = LOGB2(config.nset); - m_assoc = config.assoc; - m_line_sz = config.line_sz; - m_line_sz_log2 = LOGB2(config.line_sz); - m_replacement_policy = config.replacement_policy; - m_write_policy = config.get_write_policy(); - unsigned nlines = config.get_num_lines(); - m_lines = new cache_block_t[nlines]; + assert( m_config.m_write_policy == READ_ONLY ); + m_lines = new cache_block_t[ config.get_num_lines()]; // initialize snapshot counters for visualizer m_prev_snapshot_access = 0; m_prev_snapshot_miss = 0; - m_prev_snapshot_merge_hit = 0; + m_prev_snapshot_pending_hit = 0; m_core_id = core_id; m_type_id = type_id; } -enum cache_request_status cache_t::access( new_addr_type addr, bool write, unsigned int cycle, address_type *wb_address ) +enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx ) const { - m_access++; - unsigned set_index = (addr >> m_line_sz_log2) & ( (1<<m_nset_log2) - 1 ); - new_addr_type tag = addr >> (m_line_sz_log2 + m_nset_log2); + assert( m_config.m_write_policy == READ_ONLY ); + unsigned set_index = m_config.set_index(addr); + new_addr_type tag = m_config.tag(addr); - bool all_reserved = true; - cache_block_t *pending_line = NULL; - cache_block_t *clean_line = NULL; + unsigned invalid_line = (unsigned)-1; + unsigned valid_line = (unsigned)-1; + unsigned valid_timestamp = (unsigned)-1; - shader_cache_access_log(m_core_id, m_type_id, 0); - - for (unsigned way=0; way<m_assoc; way++) { - cache_block_t *line = &(m_lines[set_index*m_assoc+way] ); - if (line->tag == tag) { - if (line->status & RESERVED) { - pending_line = line; - break; - } else if (line->status & VALID) { - line->last_used = cycle; - if (write) - line->status |= DIRTY; - if (m_write_policy == write_through) - return HIT_W_WT; - return HIT; - } - } - if (!(line->status & RESERVED)) { - all_reserved = false; - if (!(line->status & VALID)) - clean_line = line; - } + bool all_reserved = true; + + // check for hit or pending hit + for (unsigned way=0; way<m_config.m_assoc; way++) { + unsigned index = set_index*m_config.m_assoc+way; + cache_block_t *line = &m_lines[index]; + if (line->m_tag == tag) { + if( line->m_status == RESERVED ) { + idx = index; + return HIT_RESERVED; + } else if( line->m_status == VALID ) { + idx = index; + return HIT; + } else { + assert( line->m_status == INVALID ); + } + } + if(line->m_status != RESERVED) { + all_reserved = false; + if(line->m_status == INVALID) { + invalid_line = index; + } else { + // valid line : keep track of most appropriate replacement candidate + if( m_config.m_replacement_policy == LRU ) { + if( line->m_last_access_time < valid_timestamp ) { + valid_timestamp = line->m_last_access_time; + valid_line = index; + } + } else if( m_config.m_replacement_policy == FIFO ) { + if( line->m_alloc_time < valid_timestamp ) { + valid_timestamp = line->m_alloc_time; + valid_line = index; + } + } + } + } } - m_miss++; - shader_cache_access_log(m_core_id, m_type_id, 1); - - if (pending_line || m_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( all_reserved ) { + assert( m_config.m_alloc_policy == ON_MISS ); + return RESERVATION_FAIL; // miss and not enough space in cache to allocate on miss } - // at this point: this must be a write back cache (and not a hit-under-miss) - assert( m_write_policy == write_back ); + if( invalid_line != (unsigned)-1 ) { + idx = invalid_line; + } else if( valid_line != (unsigned)-1) { + idx = valid_line; + } else abort(); // if an unreserved block exists, it is either invalid or replaceable - 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; + return MISS; +} - 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; - } +enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, unsigned &idx ) +{ + m_access++; + shader_cache_access_log(m_core_id, m_type_id, 0); // log accesses to cache + enum cache_request_status status = probe(addr,idx); + switch(status) { + case HIT_RESERVED: + m_pending_hit++; + case HIT: + m_lines[idx].m_last_access_time=time; + break; + case MISS: + m_miss++; + shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses + if( m_config.m_alloc_policy == ON_MISS ) + m_lines[idx].allocate( m_config.tag(addr), m_config.block_addr(addr), time ); + break; + case RESERVATION_FAIL: + m_miss++; + shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses + break; + } + return status; +} - // no clean lines, need to kick a line out to reserve a spot - cache_block_t *wb_line = NULL; - - for (unsigned way=0; way<m_assoc; way++) { - cache_block_t *line = &(m_lines[set_index*m_assoc+way] ); - if (line->status & VALID && !(line->status & RESERVED)) { - if (!wb_line) { - wb_line = line; - continue; - } - switch (m_replacement_policy) { - case LRU: - if (line->last_used < wb_line->last_used) - wb_line = line; - break; - case FIFO: - if (line->fetch_time < wb_line->fetch_time) - wb_line = line; - break; - default: - abort(); - } - } - } - 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 line - wb_line->status = RESERVED; - wb_line->tag = tag; - *wb_address = wb_line->addr; +void tag_array::fill( new_addr_type addr, unsigned time ) +{ + assert( m_config.m_alloc_policy == ON_FILL ); + unsigned idx; + enum cache_request_status status = probe(addr,idx); + assert(status==MISS); // MSHR should have prevented redundant memory request + m_lines[idx].allocate( m_config.tag(addr), m_config.block_addr(addr), time ); + m_lines[idx].fill(time); +} - return MISS_W_WB; +void tag_array::fill( unsigned index, unsigned time ) +{ + assert( m_config.m_alloc_policy == ON_MISS ); + m_lines[index].fill(time); } -// Obtain the windowed cache miss rate for visualizer -float cache_t::windowed_cache_miss_rate( int minus_merge_hit ) +void tag_array::flush() { - cache_t *cp = this; - unsigned int n_access = cp->m_access - cp->m_prev_snapshot_access; - unsigned int n_miss = cp->m_miss - cp->m_prev_snapshot_miss; - unsigned int n_merge_hit = cp->m_merge_hit - cp->m_prev_snapshot_merge_hit; + for (unsigned i=0; i < m_config.get_num_lines(); i++) + m_lines[i].m_status = INVALID; +} + +float tag_array::windowed_miss_rate( bool minus_pending_hit ) const +{ + unsigned n_access = m_access - m_prev_snapshot_access; + unsigned n_miss = m_miss - m_prev_snapshot_miss; + unsigned n_pending_hit = m_pending_hit - m_prev_snapshot_pending_hit; - if (minus_merge_hit) - n_miss -= n_merge_hit; + if (minus_pending_hit) + n_miss -= n_pending_hit; float missrate = 0.0f; if (n_access != 0) missrate = (float) n_miss / n_access; - return missrate; } -// start a new sampling window -void cache_t::new_window() +void tag_array::new_window() { m_prev_snapshot_access = m_access; m_prev_snapshot_miss = m_miss; - m_prev_snapshot_merge_hit = m_merge_hit; -} - -// Fetch requested data into cache line. -// Returning address on the replaced line if it is dirty, or -1 if it is clean -// Assume the line is filled all at once. -new_addr_type cache_t::fill( new_addr_type addr, unsigned int sim_cycle ) -{ - unsigned int base = 0 ; - unsigned int maxway = m_assoc; - cache_block_t *pline, *cline; - new_addr_type packed_addr = addr; - unsigned set = (packed_addr >> m_line_sz_log2) & ( (1<<m_nset_log2) - 1 ); - unsigned long long tag = packed_addr >> (m_line_sz_log2 + m_nset_log2); - - if (m_write_policy == write_back) { - //this request must have a reserved spot - cline = NULL; - for (unsigned i=base; i<maxway; i++) { - pline = &(m_lines[set*m_assoc+i] ); - if ((pline->tag == tag) && (pline->status & RESERVED)) { - cline = pline; - break; - } - if ((pline->tag == tag) && (pline->status & VALID)) { - //A second fill has returned to a line in the cache - //discard it as line in cache may have been modified, or is the same - return -1; - } - } - - 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 - - /* Fetch data into block */ - cline->status &= ~RESERVED; - cline->status |= VALID; - //cline->status &= ~DIRTY; Don't clear dirty bit, as might be dirty from write. - cline->tag = tag; - cline->addr = addr; - cline->last_used = sim_cycle; - cline->fetch_time = sim_cycle; - - // no wb, already handled. - return -1; - } - - //behavior unchanged for write through cache... probably not all necessary. - - // Look for any free slots and the possibility that the line is in the cache already - bool nofreeslot = true; - bool line_exists = false; - for (unsigned i=base; i<maxway; i++) { - pline = &(m_lines[set*m_assoc+i] ); - if (!(pline->status & VALID)) { - cline = pline; - nofreeslot = false; - break; - } else if (pline->tag == tag) { - cline = pline; - line_exists = true; - break; - } - } - - if (line_exists) { - return -1; // don't need to spill any line, nor it needs to be filled - } - - if (nofreeslot) { - cline = &(m_lines[set*m_assoc+base] ); - for (unsigned i=1+base; i<maxway; i++) { - pline = &(m_lines[set*m_assoc+i] ); - if (pline->status & VALID) { - switch (m_replacement_policy) { - case LRU: - if (pline->last_used < cline->last_used) - cline = pline; - break; - case FIFO: - if (pline->fetch_time < cline->fetch_time) - cline = pline; - break; - default: - break; - } - } - } - } - - /* Set the replaced cache line address */ - unsigned long long int repl_addr; - if ((cline->status & (DIRTY|VALID)) == (DIRTY|VALID)) { - repl_addr = cline->addr; - } else { - repl_addr = -1; - } - - /* Fetch data into block */ - cline->status |= VALID; - cline->status &= ~DIRTY; - cline->tag = tag; - cline->addr = addr; - cline->last_used = sim_cycle; - cline->fetch_time = sim_cycle; - - return repl_addr; -} - -unsigned int cache_t::flush() -{ - int dirty_lines_flushed = 0 ; - for (unsigned i = 0; i < m_nset * m_assoc ; i++) { - if ( (m_lines[i].status & (DIRTY|VALID)) == (DIRTY|VALID) ) { - dirty_lines_flushed++; - } - m_lines[i].status &= ~VALID; - m_lines[i].status &= ~DIRTY; - } - return dirty_lines_flushed; + m_prev_snapshot_pending_hit = m_pending_hit; } -void cache_t::print( FILE *stream, unsigned &total_access, unsigned &total_misses ) +void tag_array::print( FILE *stream, unsigned &total_access, unsigned &total_misses ) const { - fprintf( stream, "Cache %s:\t", m_name.c_str() ); - fprintf( stream, "Size = %d B (%d Set x %d-way x %d byte line)\n", - m_line_sz * m_nset * m_assoc, - m_nset, m_assoc, m_line_sz ); + m_config.print(stream); fprintf( stream, "\t\tAccess = %d, Miss = %d (%.3g), -MgHts = %d (%.3g)\n", m_access, m_miss, (float) m_miss / m_access, - m_miss - m_merge_hit, (float) (m_miss - m_merge_hit) / m_access); + m_miss - m_pending_hit, (float) (m_miss - m_pending_hit) / m_access); total_misses+=m_miss; total_access+=m_access; } diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h index 89a2ed0..440b98b 100644 --- a/src/gpgpu-sim/gpu-cache.h +++ b/src/gpgpu-sim/gpu-cache.h @@ -1,5 +1,5 @@ /* - * gpu-cache.c + * gpu-cache.h * * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda, * George L. Yuan and the @@ -64,57 +64,84 @@ * Vancouver, BC V6T 1Z4 */ +#ifndef GPU_CACHE_H +#define GPU_CACHE_H + #include <stdio.h> #include <stdlib.h> +#include "gpu-misc.h" +#include "mem_fetch.h" #include "../abstract_hardware_model.h" +#include "../tr1_hash_map.h" -#ifndef GPU_CACHE_H -#define GPU_CACHE_H +class mem_fetch; // mem_fetch opaque to cache and mshrs -#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_block_state { + INVALID, + RESERVED, + VALID +}; 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 - RESERVATION_FAIL, - NUM_CACHE_REQUEST_STATUS + HIT_RESERVED, + MISS, + RESERVATION_FAIL }; struct cache_block_t { cache_block_t() { - tag=0; - addr=0; - fetch_time=0; - last_used=0; - status=0; + m_tag=0; + m_block_addr=0; + m_alloc_time=0; + m_fill_time=0; + m_last_access_time=0; + m_status=INVALID; + } + void allocate( new_addr_type tag, new_addr_type block_addr, unsigned time ) + { + m_tag=tag; + m_block_addr=block_addr; + m_alloc_time=time; + m_last_access_time=time; + m_fill_time=0; + m_status=RESERVED; + } + void fill( unsigned time ) + { + assert( m_status == RESERVED ); + m_status=VALID; + m_fill_time=time; } - new_addr_type tag; - new_addr_type addr; - unsigned fetch_time; - unsigned last_used; - unsigned char status; /* valid, dirty... etc */ + + new_addr_type m_tag; + new_addr_type m_block_addr; + unsigned m_alloc_time; + unsigned m_last_access_time; + unsigned m_fill_time; + cache_block_state m_status; }; -enum replacement_policy { +enum replacement_policy_t { LRU, FIFO }; -enum write_policy { - no_writes, // line replacement when new line arrives - write_back, // line replacement when new line arrives - write_through // reservation based, use much handle reservation full error. +enum write_policy_t { + READ_ONLY, + WRITE_BACK, + WRITE_THROUGH }; -enum allocation_policy { - on_miss, - on_fill +enum allocation_policy_t { + ON_MISS, + ON_FILL +}; + +enum mshr_config_t { + TEX_FIFO, + ASSOC // normal cache }; class cache_config { @@ -127,94 +154,356 @@ public: void init() { assert( m_config_string ); - int ntok = sscanf(m_config_string,"%d:%d:%d:%c:%c:%c", &nset, &line_sz, &assoc, &replacement_policy, &write_policy, &alloc_policy); - if( ntok != 6 ) { - printf("GPGPU-Sim uArch: cache configuration parsing error (%s)\n", m_config_string ); - abort(); + char rp, wp, ap, mshr_type; + int ntok = sscanf(m_config_string,"%u:%u:%u:%c:%c:%c,%c:%u:%u,%u", + &m_nset, &m_line_sz, &m_assoc, &rp, &wp, &ap, + &mshr_type,&m_mshr_entries,&m_mshr_max_merge,&m_miss_queue_size); + if( ntok < 10 ) + exit_parse_error(); + switch(rp) { + case 'L': m_replacement_policy = LRU; break; + case 'F': m_replacement_policy = FIFO; break; + default: exit_parse_error(); + } + switch(wp) { + case 'R': m_write_policy = READ_ONLY; break; + case 'B': m_write_policy = WRITE_BACK; break; + case 'T': m_write_policy = WRITE_THROUGH; break; + default: exit_parse_error(); } + switch(ap) { + case 'm': m_alloc_policy = ON_MISS; break; + case 'f': m_alloc_policy = ON_FILL; break; + default: exit_parse_error(); + } + switch(mshr_type) { + case 'F': m_mshr_type = TEX_FIFO; break; + case 'A': m_mshr_type = ASSOC; break; + default: exit_parse_error(); + } + m_line_sz_log2 = LOGB2(m_line_sz); + m_nset_log2 = LOGB2(m_nset); m_valid = true; } unsigned get_line_sz() const { assert( m_valid ); - return line_sz; + return m_line_sz; } unsigned get_num_lines() const { assert( m_valid ); - return nset * assoc; + return m_nset * m_assoc; } - enum write_policy get_write_policy() const + void print( FILE *fp ) const { - if( write_policy == 'R' ) - return no_writes; - else if( write_policy == 'B' ) - return write_back; - else if( write_policy == 'T' ) - return write_through; - else - abort(); + fprintf( fp, "Size = %d B (%d Set x %d-way x %d byte line)\n", + m_line_sz * m_nset * m_assoc, + m_nset, m_assoc, m_line_sz ); + } + + unsigned set_index( new_addr_type addr ) const + { + return (addr >> m_line_sz_log2) & (m_nset-1); + } + new_addr_type tag( new_addr_type addr ) const + { + return addr >> (m_line_sz_log2+m_nset_log2); + } + new_addr_type block_addr( new_addr_type addr ) const + { + return addr & ~(m_line_sz-1); } char *m_config_string; private: + void exit_parse_error() + { + printf("GPGPU-Sim uArch: cache configuration parsing error (%s)\n", m_config_string ); + abort(); + } + bool m_valid; - unsigned int nset; - unsigned int line_sz; - unsigned int assoc; - unsigned char replacement_policy; // 'L' = LRU, 'F' = FIFO, 'R' = RANDOM - unsigned char write_policy; // 'T' = write through, 'B' = write back, 'R' = read only - unsigned char alloc_policy; // 'm' = allocate on miss, 'f' = allocate on fill + unsigned m_line_sz; + unsigned m_line_sz_log2; + unsigned m_nset; + unsigned m_nset_log2; + unsigned m_assoc; + + enum replacement_policy_t m_replacement_policy; // 'L' = LRU, 'F' = FIFO + enum write_policy_t m_write_policy; // 'T' = write through, 'B' = write back, 'R' = read only + enum allocation_policy_t m_alloc_policy; // 'm' = allocate on miss, 'f' = allocate on fill + enum mshr_config_t m_mshr_type; + unsigned m_mshr_entries; + unsigned m_mshr_max_merge; + unsigned m_miss_queue_size; + + friend class tag_array; friend class cache_t; }; -class cache_t { +class tag_array { public: - cache_t( const char *name, const cache_config &config, int core_id, int type_id ); - ~cache_t(); + tag_array( const cache_config &config, int core_id, int type_id ); + ~tag_array(); - enum cache_request_status access( new_addr_type addr, - bool write, - unsigned int sim_cycle, - address_type *wb_address ); + enum cache_request_status probe( new_addr_type addr, unsigned &idx ) const; + enum cache_request_status access( new_addr_type addr, unsigned time, unsigned &idx ); - new_addr_type fill( new_addr_type addr, unsigned int sim_cycle ); + void fill( new_addr_type addr, unsigned time ); + void fill( unsigned idx, unsigned time ); - unsigned flush(); - - void print( FILE *stream, unsigned &total_access, unsigned &total_misses ); - float windowed_cache_miss_rate(int); - void new_window(); + void flush(); // flash invalidate all entries + void new_window(); + + void print( FILE *stream, unsigned &total_access, unsigned &total_misses ) const; + float windowed_miss_rate( bool minus_pending_hit ) const; + +protected: -private: - std::string m_name; const cache_config &m_config; cache_block_t *m_lines; /* nbanks x nset x assoc lines in total */ - unsigned m_n_banks; - unsigned m_nset; - unsigned m_nset_log2; - unsigned m_assoc; - unsigned m_line_sz; // bytes - unsigned m_line_sz_log2; - - enum write_policy m_write_policy; - unsigned char m_replacement_policy; unsigned m_access; unsigned m_miss; - unsigned m_merge_hit; // number of cache miss that hit the same line (and merged as a result) + unsigned m_pending_hit; // number of cache miss that hit a line that is allocated but not filled // performance counters for calculating the amount of misses within a time window unsigned m_prev_snapshot_access; unsigned m_prev_snapshot_miss; - unsigned m_prev_snapshot_merge_hit; + unsigned m_prev_snapshot_pending_hit; int m_core_id; // which shader core is using this int m_type_id; // what kind of cache is this (normal, texture, constant) }; +class mshr_table { +public: + mshr_table( unsigned num_entries, unsigned max_merged ) + : m_num_entries(num_entries), + m_max_merged(max_merged), +#ifndef USE_MAP + m_data(2*num_entries) +#endif + { + } + + // is there a pending request to the lower memory level already? + bool probe( new_addr_type block_addr ) const + { + table::const_iterator a = m_data.find(block_addr); + return a != m_data.end(); + } + + // is there space for tracking a new memory access? + bool full( new_addr_type block_addr ) const + { + table::const_iterator i=m_data.find(block_addr); + if( i != m_data.end() ) + return i->second.size() >= m_max_merged; + else + return m_data.size() >= m_num_entries; + } + + // add or merge this access + void add( new_addr_type block_addr, mem_fetch *mf ) + { + m_data[block_addr].push_back(mf); + assert( m_data.size() <= m_num_entries ); + assert( m_data[block_addr].size() <= m_max_merged ); + } + + // true if cannot accept new fill responses + bool busy() const + { + return false; + } + + // accept a new cache fill response: mark entry ready for processing + void mark_ready( new_addr_type block_addr ) + { + assert( !busy() ); + table::iterator a = m_data.find(block_addr); + assert( a != m_data.end() ); // don't remove same request twice + m_current_response.push_back( block_addr ); + assert( m_current_response.size() <= m_data.size() ); + } + + // true if ready accesses exist + bool access_ready() const + { + return !m_current_response.empty(); + } + + // next ready access + mem_fetch *next_access() + { + assert( access_ready() ); + new_addr_type block_addr = m_current_response.front(); + assert( !m_data[block_addr].empty() ); + mem_fetch *result = m_data[block_addr].front(); + m_data[block_addr].pop_front(); + if( m_data[block_addr].empty() ) { + // release entry + m_data.erase(block_addr); + m_current_response.pop_front(); + } + return result; + } + + void display( FILE *fp ) const + { + fprintf(fp,"MSHR contents\n"); + for( table::const_iterator e=m_data.begin(); e!=m_data.end(); ++e ) { + unsigned block_addr = e->first; + fprintf(fp,"MSHR: tag=0x%06x, %zu entries : ", block_addr, e->second.size()); + if( !e->second.empty() ) { + mem_fetch *mf = e->second.front(); + fprintf(fp,"%p :",mf); + mf->print(fp); + } else { + fprintf(fp," no memory requests???\n"); + } + } + } + +private: + + // finite sized, fully associative table, with a finite maximum number of merged requests + const unsigned m_num_entries; + const unsigned m_max_merged; + + typedef std::list<mem_fetch*> entry; + typedef my_hash_map<new_addr_type,entry> table; + table m_data; + + // it may take several cycles to process the merged requests + bool m_current_response_ready; + std::list<new_addr_type> m_current_response; +}; + +class cache_t { +public: + cache_t( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport ) + : m_config(config), m_tag_array(config,core_id,type_id), m_mshrs(config.m_mshr_entries,config.m_mshr_max_merge) + { + m_name = name; + assert(config.m_mshr_type == ASSOC); + assert(config.m_write_policy == READ_ONLY); + m_memport=memport; + } + + // access cache: returns RESERVATION_FAIL if request could not be accepted (for any reason) + enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) + { + new_addr_type block_addr = m_config.block_addr(addr); + unsigned cache_index = (unsigned)-1; + enum cache_request_status status = m_tag_array.probe(block_addr,cache_index); + if( status == HIT ) + return HIT; + if( status != RESERVATION_FAIL ) { + bool mshr_hit = m_mshrs.probe(block_addr); + bool mshr_avail = !m_mshrs.full(block_addr); + if( mshr_hit && mshr_avail ) { + m_tag_array.access(addr,time,cache_index); + m_mshrs.add(block_addr,mf); + return MISS; + } else if( !mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size) ) { + m_tag_array.access(addr,time,cache_index); + m_mshrs.add(block_addr,mf); + m_extra_mf_fields[mf] = extra_mf_fields(block_addr,cache_index); + m_miss_queue.push_back(mf); + return MISS; + } + } + return RESERVATION_FAIL; + } + + void cycle() + { + // send next request to lower level of memory + if( !m_miss_queue.empty() ) { + mem_fetch *mf = m_miss_queue.front(); + if( !m_memport->full(mf->get_data_size(),mf->get_is_write()) ) { + m_miss_queue.pop_front(); + m_memport->push(mf); + } + } + } + + // interface for response from lower memory level (model bandwidth restictions in caller) + void fill( mem_fetch *mf, unsigned time ) + { + extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf); + assert( e != m_extra_mf_fields.end() ); + assert( e->second.m_valid ); + if ( m_config.m_alloc_policy == ON_MISS ) + m_tag_array.fill(e->second.m_cache_index,time); + else if ( m_config.m_alloc_policy == ON_FILL ) + m_tag_array.fill(e->second.m_block_addr,time); + else abort(); + m_mshrs.mark_ready(e->second.m_block_addr); + m_extra_mf_fields.erase(mf); + } + + // are any (accepted) accesses that had to wait for memory now ready? (does not include accesses that "HIT") + bool access_ready() const + { + return m_mshrs.access_ready(); + } + + // pop next ready access (does not include accesses that "HIT") + mem_fetch *next_access() + { + return m_mshrs.next_access(); + } + + // flash invalidate all entries in cache + void flush() + { + m_tag_array.flush(); + } + + void print(FILE *fp, unsigned &accesses, unsigned &misses) const + { + fprintf( fp, "Cache %s:\t", m_name.c_str() ); + m_tag_array.print(fp,accesses,misses); + } + + void display_state( FILE *fp ) const + { + fprintf(fp,"Cache %s:\n", m_name.c_str() ); + m_mshrs.display(fp); + fprintf(fp,"\n"); + } + +private: + std::string m_name; + const cache_config &m_config; + tag_array m_tag_array; + mshr_table m_mshrs; + std::list<mem_fetch*> m_miss_queue; + mem_fetch_interface *m_memport; + + struct extra_mf_fields { + extra_mf_fields() { m_valid = false; } + extra_mf_fields( new_addr_type a, unsigned i ) + { + m_block_addr = a; + m_cache_index = i; + m_valid = true; + } + bool m_valid; + new_addr_type m_block_addr; + unsigned m_cache_index; + }; + typedef std::map<mem_fetch*,extra_mf_fields> extra_mf_fields_lookup; + extra_mf_fields_lookup m_extra_mf_fields; +}; + + #endif diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index b3bc56a..0228704 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -177,14 +177,6 @@ void gpgpu_sim::reg_options(option_parser_t opp) "per-shader L1 constant memory cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}", "64:64:2:L:R:f"); - 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, &m_shader_config->m_L1D_config.m_config_string, - "shader L1 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}", - "256:128:1:L"); - option_parser_register(opp, "-gpgpu_cache:il1", OPT_CSTR, &m_shader_config->m_L1I_config.m_config_string, "shader L1 instruction cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}", "4:256:4:L:R:f"); @@ -238,10 +230,6 @@ void gpgpu_sim::reg_options(option_parser_t opp) "Number of MSHRs per shader", "64"); - 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, &m_memory_config->gpgpu_dram_sched_queue_size, "0 = unlimited (default); # entries per chip", "0"); @@ -279,15 +267,10 @@ void gpgpu_sim::reg_options(option_parser_t opp) "Stop the simulation at deadlock (1=on (default), 0=off)", "1"); - 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, &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, &m_pdom_sched_type, "0 = first ready warp found, 1 = random, 8 = loose round robin", "8"); @@ -311,12 +294,6 @@ void gpgpu_sim::reg_options(option_parser_t opp) 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, &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, &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"); @@ -438,6 +415,9 @@ void gpgpu_sim::init_gpu() set_ptx_warp_size(m_shader_config); m_shader_config->init(); + m_memory_config->init(); + + ptx_set_tex_cache_linesize(m_shader_config->m_L1T_config.get_line_sz()); 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_shader_config->n_simt_clusters*m_shader_config->n_simt_cores_per_cluster, sizeof(int)); @@ -461,15 +441,14 @@ void gpgpu_sim::init_gpu() m_memory_stats = new memory_stats_t(num_shader(),m_shader_config,m_memory_config); - m_memory_config->init(); m_memory_partition_unit = new memory_partition_unit*[m_memory_config->m_n_mem]; for (unsigned i=0;i<m_memory_config->m_n_mem;i++) m_memory_partition_unit[i] = new memory_partition_unit(i, m_memory_config, m_memory_stats); icnt_init(m_shader_config->n_simt_clusters, m_memory_config->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"); + time_vector_create(NUM_MEM_REQ_STAT); + fprintf(stdout, "GPGPU-Sim uArch: performance model initialization complete.\n"); init_clock_domains(); } @@ -637,15 +616,6 @@ unsigned int gpgpu_sim::run_gpu_sim() icnt_overal_stat(); printf("----------------------------END-of-Interconnect-DETAILS-------------------------" ); } - if (m_memory_config->gpgpu_memlatency_stat & GPU_MEMLATSTAT_QUEUELOGS ) { - for (unsigned i=0;i<m_memory_config->m_n_mem;i++) - m_memory_partition_unit[i]->queue_latency_log_dump(stdout); - if (m_memory_config->m_L2_config.get_num_lines() > 0 ) { - for(unsigned i=0; i<m_memory_config->m_n_mem; i++) - m_memory_partition_unit[i]->L2c_log(DUMPLOG); - L2c_latency_log_dump(); - } - } if (gpu_deadlock_detect && gpu_deadlock) { fflush(stdout); @@ -727,9 +697,6 @@ void gpgpu_sim::gpu_print_stat() const //for (unsigned i=0; i< m_n_shader; i++) printf("%d ", m_sc[i]->get_max_mshr_used() ); //printf("\n"); - if (m_memory_config->m_L2_config.get_num_lines()) - m_memory_stats->L2c_print_stat( m_memory_config->m_n_mem ); - for (unsigned i=0;i<m_memory_config->m_n_mem;i++) m_memory_partition_unit[i]->print(stdout); /* @@ -789,8 +756,6 @@ void gpgpu_sim::shader_print_accstats( FILE* fout ) const 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); - fprintf(fout, "gpgpu_n_partial_writes = %d\n", m_shader_stats->gpgpu_n_partial_writes); - 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]); @@ -834,7 +799,7 @@ unsigned gpgpu_sim::threads_per_core() const return m_shader_config->n_thread_per_shader; } -void gpgpu_sim::mem_instruction_stats(warp_inst_t &inst) +void gpgpu_sim::mem_instruction_stats(const warp_inst_t &inst) { //this breaks some encapsulation: the is_[space] functions, if you change those, change this. switch (inst.space.get_type()) { @@ -938,95 +903,6 @@ void shader_core_ctx::issue_block2core( kernel_info_t &kernel ) /////////////////////////////////////////////////////////////////////////////////////////// -void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle ) -{ - if (req) { - m_request_tracker.insert(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(); - m_stats->memlatstat_icnt2mem_pop(mf); - if (m_config->m_L2_config.get_num_lines()) { - if (m_config->gpgpu_l2_readoverwrite && mf->get_is_write()) - m_icnt2cache_write_queue->push(mf,gpu_sim_cycle); - else - m_icnt2cache_queue->push(mf,gpu_sim_cycle); - m_accessLocality->access(mf); - mf->set_status(IN_CBTOL2QUEUE,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } else { - m_dram->push(mf); - mf->set_status(IN_DRAM_REQ_QUEUE,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } - } -} - -mem_fetch* memory_partition_unit::pop() -{ - mem_fetch* mf; - if( m_config->m_L2_config.get_num_lines()) { - mf = L2tocbqueue->pop(gpu_sim_cycle); - if( mf && mf->isatomic() ) - mf->do_atomic(); - } else { - mf = m_dram->returnq_pop(gpu_sim_cycle); - if( mf ) { - mf->set_type( REPLY_DATA ); - if( mf->isatomic() ) - mf->do_atomic(); - } - } - m_request_tracker.erase(mf); - return mf; -} - -mem_fetch* memory_partition_unit::top() -{ - if (m_config->m_L2_config.get_num_lines()) { - return L2tocbqueue->top(); - } else { - mem_fetch* mf = m_dram->returnq_top(); - if (mf) mf->set_type( REPLY_DATA ); - return mf; - } -} - -void memory_partition_unit::issueCMD() -{ - if (m_config->m_L2_config.get_num_lines()) { - // pop completed memory request from dram and push it to dram-to-L2 queue - if ( !(dramtoL2queue->full() || dramtoL2writequeue->full()) ) { - mem_fetch* mf = m_dram->pop(); - if (mf) { - if( mf->get_mem_acc() == L2_WRBK_ACC ) { - m_request_tracker.erase(mf); - delete mf; - } else { - if (m_config->gpgpu_l2_readoverwrite && mf->get_is_write() ) - dramtoL2writequeue->push(mf,gpu_sim_cycle); - else - dramtoL2queue->push(mf,gpu_sim_cycle); - mf->set_status(IN_DRAMTOL2QUEUE,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } - } - } - } else { - if ( m_dram->returnq_full() ) - return; - mem_fetch* mf = m_dram->pop(); - if (mf) { - m_dram->returnq_push(mf,gpu_sim_cycle); - mf->set_status(IN_DRAMRETURN_Q,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } - } - m_dram->issueCMD(); - m_dram->dram_log(SAMPLELOG); -} - void dram_t::dram_log( int task ) { if (task == SAMPLELOG) { @@ -1078,25 +954,23 @@ void gpgpu_sim::cycle() for (unsigned i=0;i<m_memory_config->m_n_mem;i++) { mem_fetch* mf = m_memory_partition_unit[i]->top(); if (mf) { - mf->set_status(IN_ICNT2SHADER,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle); unsigned response_size = mf->get_is_write()?mf->get_ctrl_size():mf->size(); if ( ::icnt_has_buffer( m_shader_config->mem2device(i), response_size ) ) { if (!mf->get_is_write()) mf->set_return_timestamp(gpu_sim_cycle+gpu_tot_sim_cycle); + mf->set_status(IN_ICNT_TO_SHADER,gpu_sim_cycle+gpu_tot_sim_cycle); ::icnt_push( m_shader_config->mem2device(i), mf->get_tpc(), mf, response_size ); m_memory_partition_unit[i]->pop(); } else { gpu_stall_icnt2sh++; } - } else { - m_memory_partition_unit[i]->pop(); } } } if (clock_mask & DRAM) { for (unsigned i=0;i<m_memory_config->m_n_mem;i++) - m_memory_partition_unit[i]->issueCMD(); // Issue the dram command (scheduler + delay model) + m_memory_partition_unit[i]->dram_cycle(); // Issue the dram command (scheduler + delay model) } // L2 operations follow L2 clock domain @@ -1214,8 +1088,6 @@ void gpgpu_sim::cycle() } } - for (unsigned i=0;i<m_memory_config->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) { diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index b881806..0c1a473 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -71,7 +71,6 @@ #include "../abstract_hardware_model.h" #include "addrdec.h" -#include "gpu-cache.h" #include "shader.h" #include <list> @@ -86,7 +85,6 @@ #define GPU_RSTAT_PDOM 0x20 #define GPU_RSTAT_SCHED 0x40 #define GPU_MEMLATSTAT_MC 0x2 -#define GPU_MEMLATSTAT_QUEUELOGS 0x4 // constants for configuring merging of coalesced scatter-gather requests #define TEX_MSHR_MERGE 0x4 @@ -102,7 +100,7 @@ enum dram_ctrl_t { DRAM_FIFO=0, - DRAM_IDEAL_FAST=1 + DRAM_FRFCFS=1 }; struct memory_config { @@ -128,31 +126,30 @@ struct memory_config { char *gpgpu_dram_timing_opt; char *gpgpu_L2_queue_config; - bool gpgpu_l2_readoverwrite; bool l2_ideal; unsigned gpgpu_dram_sched_queue_size; enum dram_ctrl_t scheduler_type; bool gpgpu_memlatency_stat; unsigned m_n_mem; - unsigned int gpu_n_mem_per_ctrlr; + unsigned gpu_n_mem_per_ctrlr; // DRAM parameters - 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 - unsigned int tRCDWR; //row to column delay for a write command - unsigned int tRAS; //time needed to activate row - unsigned int tRP; //row precharge ie. deactivate row - unsigned int tRC; //row cycle time ie. precharge current, then activate different row + unsigned tCCD; //column to column delay + unsigned tRRD; //minimal time required between activation of rows in different banks + unsigned tRCD; //row to column delay - time required to activate a row before a read + unsigned tRCDWR; //row to column delay for a write command + unsigned tRAS; //time needed to activate row + unsigned tRP; //row precharge ie. deactivate row + unsigned tRC; //row cycle time ie. precharge current, then activate different row - unsigned int CL; //CAS latency - unsigned int WL; //WRITE latency - unsigned int BL; //Burst Length in bytes (we're using 4? could be 8) - unsigned int tRTW; //time to switch from read to write - unsigned int tWTR; //time to switch from write to read 5? look in datasheet - unsigned int busW; + unsigned CL; //CAS latency + unsigned WL; //WRITE latency + unsigned BL; //Burst Length in bytes (we're using 4? could be 8) + unsigned tRTW; //time to switch from read to write + unsigned tWTR; //time to switch from write to read 5? look in datasheet + unsigned busW; - unsigned int nbk; + unsigned nbk; linear_to_raw_address_translation m_address_mapping; }; @@ -195,7 +192,7 @@ public: unsigned num_shader() const { return m_shader_config->n_simt_clusters*m_shader_config->n_simt_cores_per_cluster; } unsigned threads_per_core() const; - void mem_instruction_stats( class warp_inst_t &inst); + void mem_instruction_stats( const class warp_inst_t &inst); void gpu_print_stat() const; void dump_pipeline( int mask, int s, int m ) const; @@ -213,8 +210,6 @@ private: void cycle(); 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; diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc index d2b61d7..634fa55 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -83,649 +83,211 @@ #include "shader.h" #include "mem_latency_stat.h" -template class fifo_pipeline<mem_fetch>; - -address_type L2c_mshr::cache_tag(const mem_fetch *mf) const -{ - return (mf->get_addr() & ~(m_linesize - 1)); -} - -address_type L2c_miss_tracker::cache_tag(const mem_fetch *mf) const -{ - return (mf->get_addr() & ~(m_linesize - 1)); -} - -address_type L2c_access_locality::cache_tag(const mem_fetch *mf) const -{ - return (mf->get_addr() & ~(m_linesize - 1)); -} - void gpgpu_sim::L2c_options(option_parser_t opp) { - 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_dram_partition_queues", OPT_CSTR, &m_memory_config->gpgpu_L2_queue_config, + "i2$:$2d:d2$:$2i", + "8:8:8:8"); - 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, &m_memory_config->l2_ideal, - "Use a ideal L2 cache that always hit", - "0"); + option_parser_register(opp, "-l2_ideal", OPT_BOOL, &m_memory_config->l2_ideal, + "Use a ideal L2 cache that always hit", + "0"); } +////////// -//////////////////////////////////////////////// -// L2 MSHR model - -bool L2c_mshr::new_miss(const mem_fetch *mf) -{ - address_type cacheTag = cache_tag(mf); - mem_fetch_list &missGroup = m_L2missgroup[cacheTag]; - - bool mshr_hit = not missGroup.empty(); - - missGroup.push_front(mf); - - m_n_miss += 1; - if (mshr_hit) - m_n_mshr_hits += 1; - m_entries_used += 1; - m_max_entries_used = std::max(m_max_entries_used, m_entries_used); - - return mshr_hit; -} - -void L2c_mshr::miss_serviced(const mem_fetch *mf) -{ - assert(m_active_mshr_chain.list == NULL); - address_type cacheTag = cache_tag(mf); - L2missGroup::iterator missGroup = m_L2missgroup.find(cacheTag); - if (missGroup == m_L2missgroup.end() || mf->get_type() == L2_WTBK_DATA) { - assert(mf->get_type() == L2_WTBK_DATA); // only this returning mem req can be missed by the MSHR - return; - } - assert(missGroup->first == cacheTag); - - m_active_mshr_chain.cacheTag = cacheTag; - m_active_mshr_chain.list = &(missGroup->second); - - m_n_miss_serviced_by_dram += 1; -} - -bool L2c_mshr::mshr_chain_empty() -{ - return (m_active_mshr_chain.list == NULL); -} - -mem_fetch *L2c_mshr::mshr_chain_top() -{ - const mem_fetch *mf = m_active_mshr_chain.list->back(); - assert(cache_tag(mf) == m_active_mshr_chain.cacheTag); - - return const_cast<mem_fetch*>(mf); -} - -void L2c_mshr::mshr_chain_pop() -{ - m_entries_used -= 1; - m_active_mshr_chain.list->pop_back(); - if (m_active_mshr_chain.list->empty()) { - address_type cacheTag = m_active_mshr_chain.cacheTag; - m_L2missgroup.erase(cacheTag); - m_active_mshr_chain.list = NULL; - } -} - -void L2c_mshr::print(FILE *fout) -{ - fprintf(fout, "L2c MSHR: n_entries_used = %zu\n", m_entries_used); - L2missGroup::iterator missGroup; - for (missGroup = m_L2missgroup.begin(); missGroup != m_L2missgroup.end(); ++missGroup) { - fprintf(fout, "%#08x: ", missGroup->first); - mem_fetch_list &mf_list = missGroup->second; - for (mem_fetch_list::iterator imf = mf_list.begin(); imf != mf_list.end(); ++imf) - (*imf)->print(fout); - fprintf(fout, "\n"); - } -} - -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); -} - -//////////////////////////////////////////////// -// track redundant dram access generated by L2 cache - -void L2c_miss_tracker::new_miss(mem_fetch *mf) -{ - address_type cacheTag = cache_tag(mf); - mem_fetch_set &missGroup = m_L2missgroup[cacheTag]; - - if (missGroup.size() != 0) { - m_L2redundantCnt[cacheTag] += 1; - m_totalL2redundantAcc += 1; - } - - missGroup.insert(mf); -} - -void L2c_miss_tracker::miss_serviced(mem_fetch *mf) -{ - address_type cacheTag = cache_tag(mf); - L2missGroup::iterator iMissGroup = m_L2missgroup.find(cacheTag); - if (iMissGroup == m_L2missgroup.end()) return; // this is possible for write miss - mem_fetch_set &missGroup = iMissGroup->second; - - missGroup.erase(mf); - - // remove the miss group if it goes empty - if (missGroup.empty()) { - m_L2missgroup.erase(iMissGroup); - } -} - -void L2c_miss_tracker::print(FILE *fout, bool brief) -{ - L2missGroup::iterator iMissGroup; - for (iMissGroup = m_L2missgroup.begin(); iMissGroup != m_L2missgroup.end(); ++iMissGroup) { - fprintf(fout, "%#08x: ", iMissGroup->first); - for (mem_fetch_set::iterator iMemSet = iMissGroup->second.begin(); iMemSet != iMissGroup->second.end(); ++iMemSet) { - fprintf(fout, "%p ", *iMemSet); - } - fprintf(fout, "\n"); - } -} - -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::const_iterator iL2rc = m_L2redundantCnt.begin(); iL2rc != m_L2redundantCnt.end(); ++iL2rc) { - fprintf(fout, "%#08x:%d ", iL2rc->first, iL2rc->second); - } - fprintf(fout, "\n"); -} - -//////////////////////////////////////////////// -// track all locality of L2 cache access -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) 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::const_iterator iL2rc = m_L2accCnt.begin(); iL2rc != m_L2accCnt.end(); ++iL2rc) { - locality_histo.add2bin(iL2rc->second); - } - locality_histo.fprint(fout); - fprintf(fout, "\n"); -} - -memory_partition_unit::~memory_partition_unit() -{ - delete m_mshr; - delete m_missTracker; - delete m_accessLocality; -} - -void memory_partition_unit::cache_cycle() -{ - 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->m_L2_config.get_num_lines()) { // L2 cache enabled - L2c_update_stat(); - L2c_log(SAMPLELOG); - } -} - -unsigned memory_partition_unit::L2c_get_linesize() -{ - return m_config->m_L2_config.get_line_sz(); -} - -bool memory_partition_unit::full() const -{ - if (m_config->m_L2_config.get_num_lines()) { - return m_icnt2cache_queue->full() || m_icnt2cache_write_queue->full(); - } else { - return( m_config->gpgpu_dram_sched_queue_size && m_dram->full() ); - } -} - -//////////////////////////////////////////////// -// L2 access functions - -// L2 Cache Creation memory_partition_unit::memory_partition_unit( unsigned partition_id, struct memory_config *config, class memory_stats_t *stats ) { - m_id = partition_id; - m_config=config; - m_stats=stats; - m_dram = new dram_t(m_id,m_config,m_stats); + m_id = partition_id; + m_config=config; + m_stats=stats; + m_dram = new dram_t(m_id,m_config,m_stats); - if( m_config->m_L2_config.get_num_lines() ) { - char L2c_name[32]; - snprintf(L2c_name, 32, "L2_bank_%03d", m_id); - m_L2cache = new cache_t(L2c_name,m_config->m_L2_config,-1,-1); - unsigned l2_line_sz = m_config->m_L2_config.get_line_sz(); - m_mshr = new L2c_mshr( l2_line_sz ); - m_missTracker = new L2c_miss_tracker( l2_line_sz ); - m_accessLocality = new L2c_access_locality( l2_line_sz ); - } else { - m_L2cache=NULL; - m_mshr=NULL; - m_missTracker=NULL; - m_accessLocality=NULL; - } + char L2c_name[32]; + snprintf(L2c_name, 32, "L2_bank_%03d", m_id); + m_L2interface = new L2interface(this); + m_L2cache = new cache_t(L2c_name,m_config->m_L2_config,-1,-1,m_L2interface); - unsigned int L2c_cb_L2_length; - unsigned int L2c_cb_L2w_length; - unsigned int L2c_L2_dm_length; - unsigned int L2c_dm_L2_length; - unsigned int L2c_dm_L2w_length; - unsigned int L2c_L2_cb_length; - unsigned int L2c_L2_cb_minlength; - unsigned int L2c_L2_dm_minlength; + unsigned int icnt_L2; + unsigned int L2_dram; + unsigned int dram_L2; + unsigned int L2_icnt; - 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>) - m_icnt2cache_queue = new fifo_pipeline<mem_fetch>("cbtoL2queue", 0,L2c_cb_L2_length, gpu_sim_cycle); - m_icnt2cache_write_queue = 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); - L2dramout = NULL; - wb_addr=-1; - if (m_config->m_L2_config.get_num_lines() && 1) { - cbtol2_Dist = StatCreate("cbtoL2",1, m_icnt2cache_queue->get_max_len()); - cbtoL2wr_Dist = StatCreate("cbtoL2write",1, m_icnt2cache_write_queue->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; - } + sscanf(m_config->gpgpu_L2_queue_config,"%u:%u:%u:%u", &icnt_L2,&L2_dram,&dram_L2,&L2_icnt ); + m_icnt_L2_queue = new fifo_pipeline<mem_fetch>("icnt-to-L2",0,icnt_L2); + m_L2_dram_queue = new fifo_pipeline<mem_fetch>("L2-to-dram",0,L2_dram); + m_dram_L2_queue = new fifo_pipeline<mem_fetch>("dram-to-L2",0,dram_L2); + m_L2_icnt_queue = new fifo_pipeline<mem_fetch>("L2-to-icnt",0,L2_icnt); + wb_addr=-1; } -void memory_partition_unit::L2c_service_mem_req() +memory_partition_unit::~memory_partition_unit() { - // service memory request in icnt-to-L2 queue, writing to L2 as necessary - if( L2tocbqueue->full() || L2todramqueue->full() ) - return; - mem_fetch* mf = m_icnt2cache_queue->pop(gpu_sim_cycle); - if( !mf ) - mf = m_icnt2cache_write_queue->pop(gpu_sim_cycle); - if( !mf ) - return; - switch (mf->get_type()) { - case RD_REQ: - case WT_REQ: { - address_type rep_block; - enum cache_request_status status = MISS_NO_WB; - if( mf->istexture() ) - status = m_L2cache->access( mf->get_partition_addr(), mf->get_is_write(), gpu_sim_cycle, &rep_block); - if( (status==HIT) || m_config->l2_ideal ) { - mf->set_type( REPLY_DATA ); - assert( mf != NULL ); - L2tocbqueue->push(mf,gpu_sim_cycle); - if (!mf->get_is_write()) { - m_stats->L2_read_hit++; - mf->set_return_timestamp(gpu_sim_cycle+gpu_tot_sim_cycle); - mf->set_status(IN_L2TOCBQUEUE_HIT,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } else { - m_stats->L2_write_hit++; - } - } else { - // L2 Cache Miss - // if a miss hits in 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 = m_mshr->new_miss(mf); - if (not mshr_hit) - L2todramqueue->push(mf,gpu_sim_cycle); - mf->set_status(IN_L2TODRAMQUEUE,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } - } - break; - default: assert(0); - } + delete m_icnt_L2_queue; + delete m_L2_dram_queue; + delete m_dram_L2_queue; + delete m_L2_icnt_queue; + delete m_L2cache; + delete m_L2interface; } -// service memory request in L2todramqueue, pushing to dram -void memory_partition_unit::L2c_push_miss_to_dram() +void memory_partition_unit::cache_cycle() { - if ( m_config->gpgpu_dram_sched_queue_size && m_dram->full() ) - return; - mem_fetch* mf = L2todram_wbqueue->pop(gpu_sim_cycle); //prioritize writeback - if (!mf) mf = L2todramqueue->pop(gpu_sim_cycle); - if (mf) { - if (mf->get_is_write()) - m_stats->L2_write_miss++; - else - m_stats->L2_read_miss++; - m_missTracker->new_miss(mf); - m_dram->push(mf); - mf->set_status(IN_DRAM_REQ_QUEUE, MR_DRAMQ, gpu_sim_cycle+gpu_tot_sim_cycle); - } -} + // L2 fill responses + if ( m_L2cache->access_ready() && !m_L2_icnt_queue->full() ) { + mem_fetch *mf = m_L2cache->next_access(); + mf->set_type(REPLY_DATA); + mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_icnt_queue->push(mf); + } + // DRAM to L2 (texture) and icnt (not texture) + if ( !m_dram_L2_queue->empty() ) { + mem_fetch *mf = m_dram_L2_queue->top(); + if ( mf->istexture() ) { + mf->set_status(IN_PARTITION_L2_FILL_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2cache->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_dram_L2_queue->pop(); + } else if ( !m_L2_icnt_queue->full() ) { + mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_icnt_queue->push(mf); + m_dram_L2_queue->pop(); + } + } -// service memory request in dramtoL2queue, writing to L2 as necessary -// (may cause cache eviction and subsequent writeback) -void memory_partition_unit::process_dram_output() -{ - if (L2dramout == NULL) { - // pop from mshr chain if it is not empty, otherwise, pop a new cacheline from dram output queue - if (m_mshr->mshr_chain_empty() == false) { - L2dramout = m_mshr->mshr_chain_top(); - m_mshr->mshr_chain_pop(); - } else { - L2dramout = dramtoL2queue->pop(gpu_sim_cycle); - if (!L2dramout) - L2dramout = dramtoL2writequeue->pop(gpu_sim_cycle); - if (L2dramout != NULL) { - m_mshr->miss_serviced(L2dramout); - 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* mf = L2dramout; - if (mf) { - if (!mf->get_is_write()) { //service L2 read miss - // it is a pre-fill dramout mf - if (wb_addr == (unsigned long long int)-1) { - if ( L2tocbqueue->full() ) { - assert (L2dramout || wb_addr == (unsigned long long int)-1); - return; - } - mf->set_status(IN_L2TOCBQUEUE_MISS,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - //only transfer across icnt once the whole line has been received by L2 cache - mf->set_type(REPLY_DATA); - L2tocbqueue->push(mf,gpu_sim_cycle); - if( mf->istexture() ) - wb_addr = m_L2cache->fill(mf->get_partition_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 != (unsigned long long int)-1) { - // performing L2 writeback (no false sharing for memory-side cache) - int wb_succeed = L2c_write_back(wb_addr, m_config->m_L2_config.get_line_sz()); - if (!wb_succeed) { - assert (L2dramout || wb_addr == (unsigned long long int)-1); - return; + // prior L2 misses inserted into m_L2_dram_queue here + m_L2cache->cycle(); + + // new L2 texture accesses and/or non-texture accesses + if ( !m_L2_dram_queue->full() && !m_icnt_L2_queue->empty() ) { + mem_fetch *mf = m_icnt_L2_queue->top(); + if ( mf->istexture() ) { + // in this model, L2 is for texture only + if ( !m_L2_icnt_queue->full() ) { + enum cache_request_status status = m_L2cache->access(mf->get_partition_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle); + if ( status == HIT ) { + // L2 cache replies with data + mf->set_type(REPLY_DATA); + m_L2_icnt_queue->push(mf); + m_icnt_L2_queue->pop(); + } else if ( status != RESERVATION_FAIL ) { + // L2 cache accepted request + m_icnt_L2_queue->pop(); + } else { + // L2 cache lock-up: will try again next cycle + } } - } - m_missTracker->miss_serviced(mf); - L2dramout = NULL; - wb_addr = -1; - } else { //service L2 write miss - m_missTracker->miss_serviced(mf); - mf->set_type(REPLY_DATA); - L2tocbqueue->push(mf,gpu_sim_cycle); - L2dramout = NULL; - wb_addr = -1; - } - } - assert (L2dramout || wb_addr == (unsigned long long int)-1); + } else { + // non-texture access + mf->set_status(IN_PARTITION_L2_TO_DRAM_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_dram_queue->push(mf); + m_icnt_L2_queue->pop(); + } + } } -// 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 -bool memory_partition_unit::L2c_write_back( unsigned long long int addr, int bsize ) +bool memory_partition_unit::full() const { - if ( L2todram_wbqueue->full() ) - return false; - mem_fetch *mf = new mem_fetch(addr, - bsize, - READ_PACKET_SIZE, - (unsigned)-1/*sid*/, - (unsigned)-1/*tpc*/, - (unsigned)-1/*wid*/, - (unsigned)-1/*mshr_id*/, - NULL/*inst*/, - true/*write*/, - partial_write_mask_t(), - L2_WRBK_ACC, - L2_WTBK_DATA, - m_config ); - L2todram_wbqueue->push(mf,gpu_sim_cycle); - return true; + return m_icnt_L2_queue->full(); } -void memory_partition_unit::L2c_print_cache_stat(unsigned &accesses, unsigned &misses) const +void memory_partition_unit::print_cache_stat(unsigned &accesses, unsigned &misses) const { - FILE *fp = stdout; - m_L2cache->print(fp,accesses,misses); - m_mshr->print_stat(fp); - m_missTracker->print_stat(fp); - m_accessLocality->print_stat(fp, false); + FILE *fp = stdout; + m_L2cache->print(fp,accesses,misses); } void memory_partition_unit::print( FILE *fp ) const { - if( !m_request_tracker.empty() ) { - fprintf(fp,"Memory Parition %u: pending memory requests:\n", m_id); - for( std::set<mem_fetch*>::const_iterator r=m_request_tracker.begin(); r != m_request_tracker.end(); ++r ) { - mem_fetch *mf = *r; - if( mf ) - mf->print(fp); - else - fprintf(fp," <NULL mem_fetch?>\n"); - } - } - m_dram->print(fp); -} - -void memory_partition_unit::L2c_update_stat() -{ - unsigned i=m_id; - if (m_icnt2cache_queue->get_length() > m_stats->L2_cbtoL2length[i]) - m_stats->L2_cbtoL2length[i] = m_icnt2cache_queue->get_length(); - if (m_icnt2cache_write_queue->get_length() > m_stats->L2_cbtoL2writelength[i]) - m_stats->L2_cbtoL2writelength[i] = m_icnt2cache_write_queue->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 memory_stats_t::L2c_print_stat( unsigned n_mem ) -{ - unsigned i; - - printf(" "); - for (i=0;i<n_mem;i++) { - printf(" dram[%d]", i); - } - printf("\n"); - - printf("cbtoL2 queue maximum length ="); - for (i=0;i<n_mem;i++) { - printf("%8d", L2_cbtoL2length[i]); - } - printf("\n"); - - printf("cbtoL2 write queue maximum length ="); - for (i=0;i<n_mem;i++) { - printf("%8d", L2_cbtoL2writelength[i]); - } - printf("\n"); - - printf("L2tocb queue maximum length ="); - for (i=0;i<n_mem;i++) { - printf("%8d", L2_L2tocblength[i]); - } - printf("\n"); - - printf("dramtoL2 queue maximum length ="); - for (i=0;i<n_mem;i++) { - printf("%8d", L2_dramtoL2length[i]); - } - printf("\n"); - - printf("dramtoL2 write queue maximum length ="); - for (i=0;i<n_mem;i++) { - printf("%8d", L2_dramtoL2writelength[i]); - } - printf("\n"); - - printf("L2todram queue maximum length ="); - for (i=0;i<n_mem;i++) { - printf("%8d", L2_L2todramlength[i]); - } - printf("\n"); + if ( !m_request_tracker.empty() ) { + fprintf(fp,"Memory Parition %u: pending memory requests:\n", m_id); + for ( std::set<mem_fetch*>::const_iterator r=m_request_tracker.begin(); r != m_request_tracker.end(); ++r ) { + mem_fetch *mf = *r; + if ( mf ) + mf->print(fp); + else + fprintf(fp," <NULL mem_fetch?>\n"); + } + } + m_dram->print(fp); } void memory_stats_t::print( FILE *fp ) { - 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); + 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); } void gpgpu_sim::L2c_print_cache_stat() const { - unsigned i, j, k; - for (i=0,j=0,k=0;i<m_memory_config->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); + unsigned i, j, k; + for (i=0,j=0,k=0;i<m_memory_config->m_n_mem;i++) + m_memory_partition_unit[i]->print_cache_stat(k,j); + printf("L2 Cache Total Miss Rate = %0.3f\n", (float)j/k); } -void gpgpu_sim::L2c_print_debug() -{ - unsigned i; - - printf(" "); - for (i=0;i<m_memory_config->m_n_mem;i++) - printf(" dram[%d]", i); - printf("\n"); - - printf("cbtoL2 queue length ="); - for (i=0;i<m_memory_config->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<m_memory_config->m_n_mem;i++) - printf("%8d", m_memory_partition_unit[i]->get_cbtoL2writequeue_length()); - printf("\n"); - - printf("L2tocb queue length ="); - for (i=0;i<m_memory_config->m_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_L2tocbqueue_length()); - } - printf("\n"); - - printf("dramtoL2 queue length ="); - for (i=0;i<m_memory_config->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<m_memory_config->m_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_dramtoL2writequeue_length()); - } - printf("\n"); - - printf("L2todram queue length ="); - for (i=0;i<m_memory_config->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<m_memory_config->m_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_L2todram_wbqueue_length()); - } - printf("\n"); +unsigned memory_partition_unit::flushL2() +{ + m_L2cache->flush(); + return 0; // L2 is read only in this version } -#define CREATELOG 111 -#define SAMPLELOG 222 -#define DUMPLOG 333 - -void memory_partition_unit::L2c_log(int task) +bool memory_partition_unit::busy() const { - if (task == SAMPLELOG) { - StatAddSample(cbtol2_Dist, m_icnt2cache_queue->get_length()); - StatAddSample(cbtoL2wr_Dist, m_icnt2cache_write_queue->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) { - 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); - } + return !m_request_tracker.empty(); } -unsigned memory_partition_unit::flushL2() -{ - return m_L2cache->flush(); -} - -void gpgpu_sim::L2c_latency_log_dump() +void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle ) { - for (unsigned i=0;i<m_memory_config->m_n_mem;i++) - m_memory_partition_unit[i]->L2c_latency_log_dump(); + if (req) { + m_request_tracker.insert(req); + rop_delay_t r; + r.req = req; + r.ready_cycle = cycle + 115; // Add 115*4=460 delay cycles + m_rop.push(r); + req->set_status(IN_PARTITION_ROP_DELAY,gpu_sim_cycle+gpu_tot_sim_cycle); + } + if ( !m_rop.empty() && (cycle >= m_rop.front().ready_cycle) ) { + mem_fetch* mf = m_rop.front().req; + m_rop.pop(); + m_stats->memlatstat_icnt2mem_pop(mf); + m_icnt_L2_queue->push(mf); + mf->set_status(IN_PARTITION_ICNT_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + } } -void memory_partition_unit::L2c_latency_log_dump() +mem_fetch* memory_partition_unit::pop() { - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(m_icnt2cache_queue->get_lat_stat()); - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(m_icnt2cache_write_queue->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()); + mem_fetch* mf = m_L2_icnt_queue->pop(); + if ( mf && mf->isatomic() ) + mf->do_atomic(); + m_request_tracker.erase(mf); + return mf; } -bool memory_partition_unit::busy() const +mem_fetch* memory_partition_unit::top() { - return !m_request_tracker.empty(); + return m_L2_icnt_queue->top(); } +void memory_partition_unit::dram_cycle() +{ + // pop completed memory request from dram and push it to dram-to-L2 queue + if ( !m_dram_L2_queue->full() ) { + mem_fetch* mf = m_dram->pop(); + if (mf) { + m_dram_L2_queue->push(mf); + mf->set_status(IN_PARTITION_DRAM_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + } + } + m_dram->cycle(); + m_dram->dram_log(SAMPLELOG); + + if( !m_dram->full() && !m_L2_dram_queue->empty() ) { + mem_fetch *mf = m_L2_dram_queue->pop(); + m_dram->push(mf); + } +} diff --git a/src/gpgpu-sim/l2cache.h b/src/gpgpu-sim/l2cache.h index b192986..6900394 100644 --- a/src/gpgpu-sim/l2cache.h +++ b/src/gpgpu-sim/l2cache.h @@ -67,7 +67,6 @@ #define MC_PARTITION_INCLUDED #include "dram.h" -#include "../tr1_hash_map.h" #include "../abstract_hardware_model.h" #include <list> @@ -75,156 +74,37 @@ 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, class memory_stats_t *stats ); ~memory_partition_unit(); + bool busy() const; + void cache_cycle(); + void dram_cycle(); - bool has_cache() { return m_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 flushL2(); - void L2c_print_cache_stat(unsigned &accesses, unsigned &misses) const; - unsigned get_cbtoL2queue_length() const { return m_icnt2cache_queue->get_length(); } - unsigned get_cbtoL2writequeue_length() const { return m_icnt2cache_write_queue->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(); } + unsigned flushL2(); + void visualizer_print( gzFile visualizer_file ); + void print_cache_stat(unsigned &accesses, unsigned &misses) const; 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 ) const; private: - - // 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 process_dram_output(); - - bool L2c_write_back( unsigned long long int addr, int bsize ); - - void L2c_init_stat(unsigned n_mem); - void L2c_update_stat(); - void L2c_print_debug(); - // data unsigned m_id; const struct memory_config *m_config; class dram_t *m_dram; class cache_t *m_L2cache; + class L2interface *m_L2interface; // model delay of ROP units with a fixed latency struct rop_delay_t @@ -235,32 +115,35 @@ private: std::queue<rop_delay_t> m_rop; // these are various FIFOs between units within a memory partition - fifo_pipeline<mem_fetch> *m_icnt2cache_queue; - fifo_pipeline<mem_fetch> *m_icnt2cache_write_queue; - 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; // L2 cache hit response queue - - 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 + fifo_pipeline<mem_fetch> *m_icnt_L2_queue; + fifo_pipeline<mem_fetch> *m_L2_dram_queue; + fifo_pipeline<mem_fetch> *m_dram_L2_queue; + fifo_pipeline<mem_fetch> *m_L2_icnt_queue; // L2 cache hit response queue class mem_fetch *L2dramout; unsigned long long int wb_addr; class memory_stats_t *m_stats; - 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; - std::set<mem_fetch*> m_request_tracker; + + friend class L2interface; +}; + +class L2interface : public mem_fetch_interface { +public: + L2interface( memory_partition_unit *unit ) { m_unit=unit; } + virtual bool full( unsigned size, bool write) const + { + // assume read and write packets all same size + return m_unit->m_L2_dram_queue->full(); + } + virtual void push(mem_fetch *mf) + { + m_unit->m_L2_dram_queue->push(mf); + } +private: + memory_partition_unit *m_unit; }; #endif diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc index 05835bf..0d9e4b2 100644 --- a/src/gpgpu-sim/mem_fetch.cc +++ b/src/gpgpu-sim/mem_fetch.cc @@ -77,13 +77,12 @@ mem_fetch::mem_fetch( new_addr_type addr, unsigned sid, unsigned tpc, unsigned wid, - unsigned mshr_id, warp_inst_t *inst, bool write, partial_write_mask_t partial_write_mask, enum mem_access_type mem_acc, enum mf_type type, - const memory_config *config ) + const memory_config *config ) : m_inst() { m_request_uid = sm_next_mf_request_uid++; @@ -93,7 +92,6 @@ mem_fetch::mem_fetch( new_addr_type addr, m_sid = sid; m_wid = wid; m_tpc = tpc; - m_mshr_id = mshr_id; if( inst ) m_inst = *inst; m_write = write; config->m_address_mapping.addrdec_tlx(addr,&m_raw_addr); @@ -103,20 +101,54 @@ mem_fetch::mem_fetch( new_addr_type addr, m_timestamp = gpu_sim_cycle + gpu_tot_sim_cycle; m_timestamp2 = 0; - m_status = INITIALIZED; + m_status = MEM_FETCH_INITIALIZED; + m_status_change = gpu_sim_cycle + gpu_tot_sim_cycle; } +mem_fetch::~mem_fetch() +{ + m_status = MEM_FETCH_DELETED; +} + +static const char* Status_str[] = { +"INITIALIZED", +"IN_ICNT_TO_MEM", +"IN_PARTITION_ROP_DELAY", +"IN_PARTITION_ICNT_TO_L2_QUEUE", +"IN_PARTITION_L2_TO_DRAM_QUEUE", +"IN_PARTITION_MC_INTERFACE_QUEUE", +"IN_PARTITION_MC_INPUT_QUEUE", +"IN_PARTITION_MC_BANK_ARB_QUEUE", +"IN_PARTITION_DRAM", +"IN_PARTITION_MC_RETURNQ", +"IN_PARTITION_DRAM_TO_L2_QUEUE", +"IN_PARTITION_L2_FILL_QUEUE", +"IN_PARTITION_L2_TO_ICNT_QUEUE", +"IN_ICNT_TO_SHADER", +"IN_CLUSTER_TO_SHADER_QUEUE", +"IN_SHADER_LDST_RESPONSE_FIFO", +"IN_SHADER_FETCHED", +"MEM_FETCH_DELETED", +"??", +"???" +}; + void mem_fetch::print( FILE *fp ) const { - fprintf(fp," mf: uid=%6u, addr=0x%08llx, sid=%u, wid=%u, mshr_id=%u, %s, bank=%u, ", - m_request_uid, m_addr, m_sid, m_wid, m_mshr_id, (m_write?"write":"read "), m_raw_addr.bk); + fprintf(fp," mf: uid=%6u, addr=0x%08llx, sid=%u, wid=%u, %s, partition=%u, ", + m_request_uid, m_addr, m_sid, m_wid, (m_write?"write":"read "), m_raw_addr.chip); + if( (unsigned)m_status < NUM_MEM_REQ_STAT ) + fprintf(fp," status = %s (%llu), ", Status_str[m_status], m_status_change ); + else + fprintf(fp," status = %u??? (%llu), ", m_status, m_status_change ); if( !m_inst.empty() ) m_inst.print(fp); else fprintf(fp,"\n"); } -void mem_fetch::set_status( enum mshr_status status, enum mem_req_stat stat, unsigned long long cycle ) +void mem_fetch::set_status( enum mem_fetch_status status, unsigned long long cycle ) { m_status = status; + m_status_change = cycle; } bool mem_fetch::isatomic() const @@ -139,5 +171,5 @@ bool mem_fetch::istexture() const bool mem_fetch::isconst() const { if( m_inst.empty() ) return false; - return m_inst.space.get_type() == const_space; + return (m_inst.space.get_type() == const_space) || (m_inst.space.get_type() == param_space_kernel); } diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h index c922af5..3aae63f 100644 --- a/src/gpgpu-sim/mem_fetch.h +++ b/src/gpgpu-sim/mem_fetch.h @@ -91,41 +91,26 @@ enum mem_access_type { NUM_MEM_ACCESS_TYPE = 8 }; -enum mshr_status { - INITIALIZED = 0, - INVALID, - IN_ICNT2MEM, - IN_CBTOL2QUEUE, - IN_L2TODRAMQUEUE, - IN_DRAM_REQ_QUEUE, - IN_DRAMRETURN_Q, - IN_DRAMTOL2QUEUE, - IN_L2TOCBQUEUE_HIT, - IN_L2TOCBQUEUE_MISS, - IN_ICNT2SHADER, - IN_CLUSTER2SHADER, - FETCHED, - NUM_MSHR_STATUS -}; - -//used to stages that time_vector will keep track of their timing -enum mem_req_stat { - MR_UNUSED, - MR_FQPUSHED, - MR_ICNT_PUSHED, - MR_ICNT_INJECTED, - MR_ICNT_AT_DEST, - MR_DRAMQ, //icnt_pop at dram side and mem_ctrl_push - MR_DRAM_PROCESSING_START, - MR_DRAM_PROCESSING_END, - MR_DRAM_OUTQ, - MR_2SH_ICNT_PUSHED, // icnt_push and mem_ctl_pop //STORES END HERE! - MR_2SH_ICNT_INJECTED, - MR_2SH_ICNT_AT_DEST, - MR_2SH_FQ_POP, //icnt_pop called inside fq_pop - MR_RETURN_Q, - MR_WRITEBACK, //done - NUM_MEM_REQ_STAT +enum mem_fetch_status { + MEM_FETCH_INITIALIZED = 0, + IN_ICNT_TO_MEM, + IN_PARTITION_ROP_DELAY, + IN_PARTITION_ICNT_TO_L2_QUEUE, + IN_PARTITION_L2_TO_DRAM_QUEUE, + IN_PARTITION_MC_INTERFACE_QUEUE, + IN_PARTITION_MC_INPUT_QUEUE, + IN_PARTITION_MC_BANK_ARB_QUEUE, + IN_PARTITION_DRAM, + IN_PARTITION_MC_RETURNQ, + IN_PARTITION_DRAM_TO_L2_QUEUE, + IN_PARTITION_L2_FILL_QUEUE, + IN_PARTITION_L2_TO_ICNT_QUEUE, + IN_ICNT_TO_SHADER, + IN_CLUSTER_TO_SHADER_QUEUE, + IN_SHADER_LDST_RESPONSE_FIFO, + IN_SHADER_FETCHED, + MEM_FETCH_DELETED, + NUM_MEM_REQ_STAT }; const unsigned partial_write_mask_bits = 128; //must be at least size of largest memory access. @@ -139,15 +124,15 @@ public: unsigned sid, unsigned tpc, unsigned wid, - unsigned mshr_id, warp_inst_t *inst, bool write, partial_write_mask_t partial_write_mask, enum mem_access_type mem_acc, enum mf_type type, const class memory_config *config ); + ~mem_fetch(); - void set_status( enum mshr_status status, enum mem_req_stat stat, unsigned long long cycle ); + void set_status( enum mem_fetch_status status, unsigned long long cycle ); void set_type( enum mf_type t ) { m_type=t; } void do_atomic(); @@ -159,7 +144,6 @@ public: unsigned size() const { return m_data_size+m_ctrl_size; } new_addr_type get_addr() const { return m_addr; } new_addr_type get_partition_addr() const { return m_partition_addr; } - unsigned get_mshr() { return m_mshr_id; } bool get_is_write() const { return m_write; } unsigned get_request_uid() const { return m_request_uid; } unsigned get_sid() const { return m_sid; } @@ -177,7 +161,7 @@ public: enum mem_access_type get_mem_acc() const { return m_mem_acc; } address_type get_pc() const { return m_inst.empty()?-1:m_inst.pc; } const warp_inst_t &get_inst() { return m_inst; } - enum mshr_status get_status() const { return m_status; } + enum mem_fetch_status get_status() const { return m_status; } private: // request source information @@ -185,10 +169,10 @@ private: unsigned m_sid; unsigned m_tpc; unsigned m_wid; - unsigned m_mshr_id; // where is this request now? - enum mshr_status m_status; + enum mem_fetch_status m_status; + unsigned long long m_status_change; // request type, address, size, mask bool m_write; diff --git a/src/gpgpu-sim/mem_latency_stat.cc b/src/gpgpu-sim/mem_latency_stat.cc index 2087fd2..f78717e 100644 --- a/src/gpgpu-sim/mem_latency_stat.cc +++ b/src/gpgpu-sim/mem_latency_stat.cc @@ -79,8 +79,11 @@ #include <stdlib.h> #include <stdio.h> -memory_stats_t::memory_stats_t( unsigned n_shader, struct shader_core_config *shader_config, struct memory_config *mem_config ) +memory_stats_t::memory_stats_t( unsigned n_shader, const struct shader_core_config *shader_config, const struct memory_config *mem_config ) { + assert( mem_config->m_valid ); + assert( shader_config->m_valid ); + unsigned i,j; @@ -119,7 +122,6 @@ memory_stats_t::memory_stats_t( unsigned n_shader, struct shader_core_config *sh 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(mem_config->m_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; diff --git a/src/gpgpu-sim/mem_latency_stat.h b/src/gpgpu-sim/mem_latency_stat.h index 14868ef..b7e4b64 100644 --- a/src/gpgpu-sim/mem_latency_stat.h +++ b/src/gpgpu-sim/mem_latency_stat.h @@ -73,8 +73,8 @@ class memory_stats_t { public: memory_stats_t( unsigned n_shader, - struct shader_core_config *shader_config, - struct memory_config *mem_config ); + const struct shader_core_config *shader_config, + const struct memory_config *mem_config ); unsigned memlatstat_done( class mem_fetch *mf, unsigned n_warp_per_shader ); void memlatstat_read_done( class mem_fetch *mf, unsigned n_warp_per_shader); @@ -83,8 +83,6 @@ public: 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 L2c_print_stat(unsigned n_mem); - void print( FILE *fp ); unsigned m_n_shader; @@ -121,7 +119,6 @@ public: 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 diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 2c5de09..1f0ebc4 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -88,195 +88,7 @@ #define PRIORITIZE_MSHR_OVER_WB 1 #define MAX(a,b) (((a)>(b))?(a):(b)) - ///////////////////////////////////////////////////////////////////////////// -/*-------------------------------------------------------------------------*/ -/*-------------------------------------------------------------------------*/ - -static const char* MSHR_Status_str[] = { - "INITIALIZED", - "INVALID", - "IN_ICNT2MEM", - "IN_CBTOL2QUEUE", - "IN_L2TODRAMQUEUE", - "IN_DRAM_REQ_QUEUE", - "IN_DRAMRETURN_Q", - "IN_DRAMTOL2QUEUE", - "IN_L2TOCBQUEUE_HIT", - "IN_L2TOCBQUEUE_MISS", - "IN_ICNT2SHADER", - "IN_CLUSTER2SHADER", - "FETCHED", -}; - -void mshr_lookup::insert(mshr_entry* mshr) -{ - using namespace std; - new_addr_type tag_addr = mshr->get_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(); - } -} - -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); - - 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; - } - } -} - -//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->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_lookup::mshr_fast_lookup_remove(mshr_entry* mshr) -{ - if (!can_merge(mshr)) - return; - remove(mshr); -} - -mshr_entry* mshr_lookup::shader_get_mergeable_mshr(mshr_entry* mshr) -{ - if (!can_merge(mshr)) return NULL; - return lookup(mshr->get_addr()); -} - -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); - } -} - -mshr_entry* mshr_shader_unit::return_head() -{ - if (has_return()) - return &(*choose_return_queue().front()); - else - return NULL; -} - -void mshr_shader_unit::pop_return_head() -{ - free_mshr(return_head()); - choose_return_queue().pop_front(); -} - -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(); -} - -std::list<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; -} - -void mshr_shader_unit::mshr_return_from_mem(unsigned mshr_id) -{ - if(mshr_id == (unsigned)-1) { - return; - } - mshr_entry *mshr = &m_mshrs[mshr_id]; - mshr->set_fetched(); - mem_fetch *mf = mshr->get_mf(); - if( mf ) mf->set_status( FETCHED, MR_RETURN_Q, gpu_sim_cycle+gpu_tot_sim_cycle ); - if ( not mshr->istexture() ) { - //place in return queue - mshr->add_to_queue( m_mshr_return_queue ); - } -} - -void mshr_shader_unit::print(FILE* fp) -{ - 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); - } - } - fprintf(fp,"ready texture mshrs:\n"); - std::list<mshr_entry*>::iterator m; - for( m=m_texture_mshr_pipeline.begin(); m!=m_texture_mshr_pipeline.end(); m++ ) { - mshr_entry *mshr = *m; - mshr->print(fp); - } - fprintf(fp,"ready non-texture mshrs:\n"); - for( m=m_mshr_return_queue.begin(); m!=m_mshr_return_queue.end(); m++ ) { - mshr_entry *mshr = *m; - mshr->print(fp); - } - fprintf(fp,"outstanding memory requests = %u\n", num_outstanding ); -} - std::list<unsigned> shader_core_ctx::get_regs_written( const inst_t &fvt ) const { @@ -322,6 +134,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_thread[i].m_functional_model_thread_state = NULL; m_thread[i].m_cta_id = -1; } + + m_icnt = new shader_memory_interface(cluster); // fetch m_last_warp_fetched = 0; @@ -330,7 +144,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, #define STRSIZE 1024 char L1I_name[STRSIZE]; snprintf(L1I_name, STRSIZE, "L1I_%03d", m_sid); - m_L1I = new cache_t(L1I_name,m_config->m_L1I_config,m_sid,get_shader_instruction_cache_id()); + m_L1I = new cache_t(L1I_name,m_config->m_L1I_config,m_sid,get_shader_instruction_cache_id(),m_icnt); m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size)); m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader]; @@ -364,7 +178,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_dispatch_port[1] = ID_OC_SFU; m_issue_port[1] = OC_EX_SFU; - m_ldst_unit = new ldst_unit( cluster, this, &m_operand_collector, m_scoreboard, config, mem_config, stats, shader_id, tpc_id ); + m_ldst_unit = new ldst_unit( m_icnt, this, &m_operand_collector, m_scoreboard, config, mem_config, stats, shader_id, tpc_id ); m_fu[2] = m_ldst_unit; m_dispatch_port[2] = ID_OC_MEM; m_issue_port[2] = OC_EX_MEM; @@ -607,43 +421,47 @@ void shader_core_ctx::fetch() 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_config->m_L1I_config.get_line_sz()-1); if( (offset_in_block+nbytes) > m_config->m_L1I_config.get_line_sz() ) nbytes = (m_config->m_L1I_config.get_line_sz()-offset_in_block); - enum cache_request_status status = m_L1I->access( (unsigned long long)pc, 0, gpu_sim_cycle, &wb ); - if( status != HIT ) { - unsigned req_size = READ_PACKET_SIZE; - if( !m_cluster->icnt_injection_buffer_full(ppc, req_size, false) ) { - m_last_warp_fetched=warp_id; - mem_fetch *mf = new mem_fetch(pc, - req_size, - READ_PACKET_SIZE, - m_sid, - m_tpc, - warp_id, - (unsigned)-1/*mshr_id*/, - NULL/*we don't have an instruction yet*/, - false, - NO_PARTIAL_WRITE, - INST_ACC_R, - RD_REQ, - m_memory_config ); - m_cluster->icnt_inject_request_packet(mf); - - m_warp[warp_id].set_imiss_pending(); - m_warp[warp_id].set_last_fetch(gpu_sim_cycle); - } - } else { + mem_fetch *mf = new mem_fetch(ppc, + nbytes, + READ_PACKET_SIZE, + m_sid, + m_tpc, + warp_id, + NULL/*we don't have an instruction yet*/, + false, + NO_PARTIAL_WRITE, + INST_ACC_R, + RD_REQ, + m_memory_config ); + enum cache_request_status status = m_L1I->access( (new_addr_type)ppc, mf, gpu_sim_cycle+gpu_tot_sim_cycle ); + if( status == MISS ) { + m_last_warp_fetched=warp_id; + m_warp[warp_id].set_imiss_pending(); + m_warp[warp_id].set_last_fetch(gpu_sim_cycle); + } else if( status == HIT ) { 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); + } else { + assert( status == RESERVATION_FAIL ); + delete mf; } break; } } } + + m_L1I->cycle(); + + if( m_L1I->access_ready() ) { + mem_fetch *mf = m_L1I->next_access(); + m_warp[mf->get_wid()].clear_imiss_pending(); + delete mf; + } } void shader_core_ctx::func_exec_inst( warp_inst_t &inst ) @@ -791,178 +609,53 @@ void shader_core_ctx::execute() } } -mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* pinst) -{ - // creates an mshr based on the access struct information - mshr_entry* mshr = alloc_free_mshr(pinst->space == tex_space); - mshr->init(access.addr,pinst->is_store(),pinst->space,pinst->warp_id()); - warp_inst_t inst = *pinst; - inst.set_active(access.warp_indices); - mshr->add_inst(inst); - 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->get_id()); - } - m_mshr_lookup.mshr_fast_lookup_insert(mshr); - } - return mshr; -} - -void ldst_unit::const_cache_access(warp_inst_t &inst) +mem_fetch *ldst_unit::create_data_mem_fetch(warp_inst_t &inst, mem_access_t &access) { - // 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 = 0; i < inst.get_accessq_size(); i++) { - mem_access_t &req = inst.accessq(i); - if ( inst.space == param_space_kernel ) { - req.cache_hit = true; - } else { - cache_request_status status = m_L1C->access( req.addr, - 0, //should always be a read - gpu_sim_cycle+gpu_tot_sim_cycle, - NULL/*should never writeback*/); - req.cache_hit = (status == HIT); - if (m_config->gpgpu_perfect_mem) req.cache_hit = true; - if (req.cache_hit) m_stats->L1_const_miss++; - } - req.cache_checked = true; + bool is_write = inst.is_store(); + mem_access_type access_type; + switch (inst.space.get_type()) { + case const_space: + case param_space_kernel: + access_type = CONST_ACC_R; + break; + case tex_space: + access_type = TEXTURE_ACC_R; + break; + case global_space: + access_type = is_write? GLOBAL_ACC_W: GLOBAL_ACC_R; + break; + case local_space: + case param_space_local: + access_type = is_write? LOCAL_ACC_W: LOCAL_ACC_R; + break; + default: assert(0); break; } -} - -void ldst_unit::tex_cache_access(warp_inst_t &inst) -{ - // 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 = 0; i < inst.get_accessq_size(); i++) { - mem_access_t &req = inst.accessq(i); - cache_request_status status = m_L1T->access( req.addr, - 0, //should always be a read - gpu_sim_cycle+gpu_tot_sim_cycle, - NULL /*should never writeback*/); - req.cache_hit = (status == HIT); - if (m_config->gpgpu_perfect_mem) req.cache_hit = true; - if (req.cache_hit) m_stats->L1_texture_miss++; - req.cache_checked = true; - } -} - -mem_stage_stall_type ldst_unit::send_mem_request(warp_inst_t &inst, mem_access_t &access) -{ - // Attempt to send an request/write to memory based on information in access. - - // 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) { - unsigned req_size = m_config->gpgpu_cache_dl1_linesize + WRITE_PACKET_SIZE; - if ( m_cluster->icnt_injection_buffer_full(access.wb_addr, req_size, true) ) { - m_stats->gpu_stall_sh2icnt++; - return WB_ICNT_RC_FAIL; - } - mem_fetch *mf = new mem_fetch(access.wb_addr, - req_size, - READ_PACKET_SIZE, - m_sid, - m_tpc, - -1/*wid*/, - -1/*mshr id*/, - NULL, - true, - NO_PARTIAL_WRITE, - inst.space.is_local()?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request - WT_REQ, - m_memory_config ); - m_cluster->icnt_inject_request_packet(mf); - inst.clear_active(access.warp_indices); - m_stats->L1_writeback++; - access.need_wb = false; - } - - bool is_write = inst.is_store(); - mem_access_type access_type; - bool requires_mshr = false; - switch(inst.space.get_type()) { - case const_space: - case param_space_kernel: - access_type = CONST_ACC_R; - break; - case tex_space: - access_type = TEXTURE_ACC_R; - break; - case global_space: - access_type = is_write? GLOBAL_ACC_W: GLOBAL_ACC_R; - break; - case local_space: - case param_space_local: - access_type = is_write? LOCAL_ACC_W: LOCAL_ACC_R; - break; - default: assert(0); break; - } - //reserve mshr - if (requires_mshr && !access.reserved_mshr) { - if (not m_mshr_unit->has_mshr(1)) - return MSHR_RC_FAIL; - access.reserved_mshr = m_mshr_unit->add_mshr(access, &inst); - 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 = (!access.reserved_mshr) || (!access.reserved_mshr->ismerged()); - if (requires_icnt) { - //calculate request size for icnt check (and later send); - unsigned request_size = access.req_size; - if (is_write) { - 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 - } - if ( m_cluster->icnt_injection_buffer_full(access.addr, request_size, is_write) ) { - // can't allocate icnt - m_stats->gpu_stall_sh2icnt++; - return ICNT_RC_FAIL; - } - //send over interconnect - partial_write_mask_t write_mask = NO_PARTIAL_WRITE; - unsigned warp_id = inst.warp_id(); - if (is_write) { - m_core->inc_store_req(warp_id); - for (unsigned i=0;i < access.warp_indices.size();i++) { + unsigned request_size = access.req_size; + partial_write_mask_t write_mask = NO_PARTIAL_WRITE; + if (is_write) { + for (unsigned i=0;i < access.warp_indices.size();i++) { unsigned w = access.warp_indices[i]; int data_offset = inst.get_addr(w) & ((unsigned long long int)access.req_size - 1); - for (unsigned b = data_offset; b < data_offset + inst.data_size; b++) write_mask.set(b); - } - if (write_mask.count() != access.req_size) - m_stats->gpgpu_n_partial_writes++; - } - unsigned mshr_id = access.reserved_mshr?access.reserved_mshr->get_id():-1; - warp_inst_t inst_copy = inst; - inst_copy.set_active(access.warp_indices); - mem_fetch *mf = new mem_fetch(access.addr, - request_size, - is_write?WRITE_PACKET_SIZE:READ_PACKET_SIZE, - m_sid, - m_tpc, - warp_id, - mshr_id, - &inst_copy, - is_write, - write_mask, - access_type, - is_write?WT_REQ:RD_REQ, - m_memory_config); - if( access.reserved_mshr ) - access.reserved_mshr->set_mf(mf); - m_cluster->icnt_inject_request_packet(mf); - if( inst.is_load() ) { - for( unsigned r=0; r < 4; r++) - if(inst.out[r] > 0) - m_pending_writes[inst.warp_id()][inst.out[r]]++; - } - } - return NO_RC_FAIL; + for (unsigned b = data_offset; b < data_offset + inst.data_size; b++) + write_mask.set(b); + } + } + warp_inst_t inst_copy = inst; + inst_copy.set_active(access.warp_indices); + unsigned warp_id = inst.warp_id(); + mem_fetch *mf = new mem_fetch(access.addr, + request_size, + is_write?WRITE_PACKET_SIZE:READ_PACKET_SIZE, + m_sid, + m_tpc, + warp_id, + &inst_copy, + is_write, + write_mask, + access_type, + is_write?WT_REQ:RD_REQ, + m_memory_config); + return mf; } void shader_core_ctx::writeback() @@ -1003,54 +696,40 @@ bool ldst_unit::shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, return inst.accessq_empty(); //done if empty. } -mem_stage_stall_type ldst_unit::process_memory_access_queue( ldst_unit::cache_check_t cache_check, - unsigned ports_per_bank, - unsigned memory_send_max, - warp_inst_t &inst ) +mem_stage_stall_type ldst_unit::process_memory_access_queue( cache_t *cache, warp_inst_t &inst ) { - // 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 (inst.accessq_empty()) - break; - unsigned current_order = inst.accessq_back().order; - // consume all requests of the same "order" but stop if we hit a structural hazard - while( !inst.accessq_empty() && inst.accessq_back().order == current_order && hazard_cond == NO_RC_FAIL) { - hazard_cond = (this->*cache_check)(inst,inst.accessq_back()); - if (hazard_cond != NO_RC_FAIL) - break; // can't complete this request this cycle. - if ( !inst.accessq_back().cache_hit ){ - if (mem_req_count < memory_send_max) { - mem_req_count++; - hazard_cond = send_mem_request(inst,inst.accessq_back()); - } - 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. - } - inst.accessq_pop_back(); - } - } - if (!inst.accessq_empty() && hazard_cond == NO_RC_FAIL) { - //no resource failed so must be a bank comflict. - hazard_cond = BK_CONF; - } - return hazard_cond; -} + mem_stage_stall_type result = NO_RC_FAIL; + unsigned current_order = inst.accessq_back().order; + while ((!inst.accessq_empty()) && inst.accessq_back().order == current_order) { + mem_fetch *mf = create_data_mem_fetch(inst,inst.accessq_back()); + enum cache_request_status status = cache->access(mf->get_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle); + if( status == HIT ) { + inst.accessq_pop_back(); + delete mf; + } else if( status == RESERVATION_FAIL ) { + result = COAL_STALL; // todo: unify enums + delete mf; + break; + } else { + assert( status == MISS ); + inst.accessq_pop_back(); + if( inst.is_load() ) { + for( unsigned r=0; r < 4; r++) + if(inst.out[r] > 0) + m_pending_writes[inst.warp_id()][inst.out[r]]++; + } + } + } + if( !inst.accessq_empty() && (inst.accessq_back().order != current_order) ) + result = BK_CONF; + return result; +} bool ldst_unit::constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { if( (inst.space.get_type() != const_space) && (inst.space.get_type() != param_space_kernel) ) return true; - - // Process a single cycle of activity from the the constant memory queue. - mem_stage_stall_type fail = process_memory_access_queue(&ldst_unit::ccache_check, - m_config->gpgpu_const_port_per_bank, - 1, //memory send max per cycle - inst ); + mem_stage_stall_type fail = process_memory_access_queue(m_L1C,inst); if (fail != NO_RC_FAIL){ rc_fail = fail; //keep other fails if this didn't fail. fail_type = C_MEM; @@ -1065,13 +744,7 @@ bool ldst_unit::texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, { if( inst.space.get_type() != tex_space ) return true; - - // Process a single cycle of activity from the the texture memory queue. - - mem_stage_stall_type fail = process_memory_access_queue(&ldst_unit::tcache_check, - 1, //how is tex memory banked? - 1, //memory send max per cycle - inst ); + mem_stage_stall_type fail = process_memory_access_queue(m_L1T,inst); if (fail != NO_RC_FAIL){ rc_fail = fail; //keep other fails if this didn't fail. fail_type = T_MEM; @@ -1079,77 +752,32 @@ bool ldst_unit::texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, return inst.accessq_empty(); //done if empty. } -mem_stage_stall_type ldst_unit::dcache_check(warp_inst_t &inst, 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 && !access.recheck_cache) - return NO_RC_FAIL; - if (!m_config->gpgpu_no_dl1 && !m_config->gpgpu_perfect_mem) { - //check cache - cache_request_status status = m_L1D->access( access.addr, - inst.is_store(), - gpu_sim_cycle+gpu_tot_sim_cycle, - &access.wb_addr ); - if (status == RESERVATION_FAIL) { - access.cache_checked = false; - return WB_CACHE_RSRV_FAIL; - } - access.cache_hit = (status == HIT); //if HIT_W_WT then still send to memory so "MISS" - if (status == MISS_W_WB) - access.need_wb = true; - if (status == WB_HIT_ON_MISS && inst.is_store()) - { - //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; - 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 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). - } - if (status == WB_HIT_ON_MISS && !inst.is_store() ) { - //read has hit on a reserved cache line, - //we need to make sure cache check happens on same cycle as a mshr merge happens, otherwise we might miss it coming back - access.recheck_cache = true; - } - access.cache_checked = true; - } else { - access.cache_hit = false; - } - - if (m_config->gpgpu_perfect_mem) - access.cache_hit = true; - - if (inst.isatomic()) { - if (m_config->gpgpu_perfect_mem) { - // complete functional execution of atomic here - inst.do_atomic(); - } else { - // atomics always go to memory - access.cache_hit = false; - } - } - - if (!access.cache_hit) { - if (inst.is_store()) m_stats->L1_write_miss++; - else m_stats->L1_read_miss++; - } - return NO_RC_FAIL; -} - bool ldst_unit::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type ) { if( (inst.space.get_type() != global_space) && (inst.space.get_type() != local_space) && (inst.space.get_type() != param_space_local) ) return true; - - // Process a single cycle of activity from the the global/local memory queue. - mem_stage_stall_type stall_cond = process_memory_access_queue(&ldst_unit::dcache_check,m_config->gpgpu_cache_port_per_bank,1,inst); + mem_stage_stall_type stall_cond = NO_RC_FAIL; + unsigned current_order = inst.accessq_back().order; + while ((!inst.accessq_empty()) && inst.accessq_back().order == current_order) { + if( m_icnt->full(inst.accessq_back().req_size, inst.is_store()) ) { + stall_cond = ICNT_RC_FAIL; + break; + } else { + mem_fetch *mf = create_data_mem_fetch(inst,inst.accessq_back()); + m_icnt->push(mf); + inst.accessq_pop_back(); + if( inst.is_load() ) { + for( unsigned r=0; r < 4; r++) + if(inst.out[r] > 0) + m_pending_writes[inst.warp_id()][inst.out[r]]++; + } else if( inst.is_store() ) + m_core->inc_store_req( inst.warp_id() ); + } + } + if( !inst.accessq_empty() ) + stall_cond = COAL_STALL; if (stall_cond != NO_RC_FAIL) { stall_reason = stall_cond; bool iswrite = inst.is_store(); @@ -1170,33 +798,13 @@ bool ldst_unit::response_buffer_full() const void ldst_unit::fill( mem_fetch *mf ) { + mf->set_status(IN_SHADER_LDST_RESPONSE_FIFO,gpu_sim_cycle+gpu_tot_sim_cycle); m_response_fifo.push_back(mf); } void ldst_unit::flush() { - m_L1D->flush(); - // TODO: add flush 'interface' object to provide functionality commented out below - /* - - unsigned int i; - unsigned int set; - unsigned long long int flush_addr; - cache_t *cp = m_L1D; - cache_block_t *pline; - for (i=0; i<cp->m_nset*cp->m_assoc; i++) { - pline = &(cp->m_lines[i]); - set = i / cp->m_assoc; - if ((pline->status & (DIRTY|VALID)) == (DIRTY|VALID)) { - flush_addr = pline->addr; - fq_push(flush_addr, m_L1D->get_line_sz(), 1, NO_PARTIAL_WRITE, 0, NULL, 0, GLOBAL_ACC_W, -1); - pline->status &= ~VALID; - pline->status &= ~DIRTY; - } else if (pline->status & VALID) { - pline->status &= ~VALID; - } - } - */ + // no L1D } void ldst_unit::generate_mem_accesses(warp_inst_t &inst) @@ -1210,19 +818,9 @@ void ldst_unit::generate_mem_accesses(warp_inst_t &inst) if( inst.mem_accesses_created() ) return; inst.get_memory_access_list(); - switch( inst.space.get_type() ) { - case shared_space: break; - case tex_space: tex_cache_access(inst); break; - case const_space: case param_space_kernel: const_cache_access(inst); break; - case global_space: case local_space: case param_space_local: break; - case param_space_unclassified: abort(); break; - default: break; // non-memory operations - } - m_cluster->mem_instruction_stats(inst); inst.set_mem_accesses_created(); } - simd_function_unit::simd_function_unit( const shader_core_config *config ) { m_config=config; @@ -1252,7 +850,7 @@ pipelined_simd_unit::pipelined_simd_unit( warp_inst_t **result_port, const shade m_pipeline_reg[i] = new warp_inst_t( config ); } -ldst_unit::ldst_unit( simt_core_cluster *cluster, +ldst_unit::ldst_unit( shader_memory_interface *icnt, shader_core_ctx *core, opndcoll_rfu_t *operand_collector, Scoreboard *scoreboard, @@ -1260,10 +858,10 @@ ldst_unit::ldst_unit( simt_core_cluster *cluster, const memory_config *mem_config, shader_core_stats *stats, unsigned sid, - unsigned tpc ) : pipelined_simd_unit(NULL,config,6) + unsigned tpc ) : pipelined_simd_unit(NULL,config,6), m_next_wb(config) { m_memory_config = mem_config; - m_cluster = cluster; + m_icnt = icnt; m_core = core; m_operand_collector = operand_collector; m_scoreboard = scoreboard; @@ -1271,64 +869,74 @@ ldst_unit::ldst_unit( simt_core_cluster *cluster, m_sid = sid; m_tpc = tpc; #define STRSIZE 1024 - char L1D_name[STRSIZE]; char L1T_name[STRSIZE]; char L1C_name[STRSIZE]; - snprintf(L1D_name, STRSIZE, "L1D_%03d", m_sid); snprintf(L1T_name, STRSIZE, "L1T_%03d", m_sid); snprintf(L1C_name, STRSIZE, "L1C_%03d", m_sid); - m_L1D = new cache_t(L1D_name,m_config->m_L1D_config,m_sid,get_shader_normal_cache_id()); - m_L1T = new cache_t(L1T_name,m_config->m_L1T_config,m_sid,get_shader_texture_cache_id()); - m_L1C = new cache_t(L1C_name,m_config->m_L1C_config,m_sid,get_shader_constant_cache_id()); - m_cluster->get_gpu()->ptx_set_tex_cache_linesize(m_config->m_L1T_config.get_line_sz()); - m_mshr_unit = new mshr_shader_unit(m_config); + m_L1T = new cache_t(L1T_name,m_config->m_L1T_config,m_sid,get_shader_texture_cache_id(),icnt); + m_L1C = new cache_t(L1C_name,m_config->m_L1C_config,m_sid,get_shader_constant_cache_id(),icnt); m_mem_rc = NO_RC_FAIL; + m_num_writeback_clients=4; // = shared memory, global/local, L1T, L1C + m_writeback_arb = 0; + m_next_global=NULL; } void ldst_unit::writeback() { - mshr_entry *m = m_mshr_unit->return_head(); - if( m ) m_mshr_unit->pop_return_head(); - - if( !m_pipeline_reg[0]->empty() ) { - // shared memory has priority - if( m_operand_collector->writeback(*m_pipeline_reg[0]) ) { - m_scoreboard->releaseRegisters(m_pipeline_reg[0]); - m_core->dec_inst_in_pipeline(m_pipeline_reg[0]->warp_id()); - m_pipeline_reg[0]->clear(); - } - } - - if( !m_response_fifo.empty() ) { - mem_fetch *mf = m_response_fifo.front(); - if( mf->get_is_write() ) { - m_core->store_ack(mf); - m_response_fifo.pop_front(); - } else { - const warp_inst_t &inst = mf->get_inst(); - if( m_operand_collector->writeback(inst) ) { - m_response_fifo.pop_front(); - if( mf->isatomic() ) - m_core->decrement_atomic_count(mf->get_wid(),inst.active_count()); - for( unsigned r=0; r < 4; r++ ) { - if( inst.out[r] > 0 ) { - assert( m_pending_writes[inst.warp_id()][inst.out[r]] > 0 ); - unsigned still_pending = --m_pending_writes[inst.warp_id()][inst.out[r]]; + // process next instruction that is going to writeback + if( !m_next_wb.empty() ) { + if( m_operand_collector->writeback(m_next_wb) ) { + for( unsigned r=0; r < 4; r++ ) { + if( m_next_wb.out[r] > 0 ) { + if( m_next_wb.space.get_type() != shared_space ) { + assert( m_pending_writes[m_next_wb.warp_id()][m_next_wb.out[r]] > 0 ); + unsigned still_pending = --m_pending_writes[m_next_wb.warp_id()][m_next_wb.out[r]]; if( !still_pending ) { - m_pending_writes[inst.warp_id()].erase(inst.out[r]); - m_scoreboard->releaseRegister( inst.warp_id(), inst.out[r] ); + m_pending_writes[m_next_wb.warp_id()].erase(m_next_wb.out[r]); + m_scoreboard->releaseRegister( m_next_wb.warp_id(), m_next_wb.out[r] ); } - } + } else // shared + m_scoreboard->releaseRegister( m_next_wb.warp_id(), m_next_wb.out[r] ); } - m_mshr_unit->mshr_return_from_mem(mf->get_mshr()); - if (mf->istexture()) - m_L1T->fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle); - else if (mf->isconst()) - m_L1C->fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle); - else if (!m_config->gpgpu_no_dl1) - m_L1D->fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle); + } + m_next_wb.clear(); + } + } + + for( unsigned c=0; m_next_wb.empty() && (c < m_num_writeback_clients); c++ ) { + unsigned next_client = (c+m_writeback_arb)%m_num_writeback_clients; + switch( next_client ) { + case 0: // shared memory + if( !m_pipeline_reg[0]->empty() ) { + m_next_wb = *m_pipeline_reg[0]; + m_core->dec_inst_in_pipeline(m_pipeline_reg[0]->warp_id()); + m_pipeline_reg[0]->clear(); + } + break; + case 1: // texture response + if( m_L1T->access_ready() ) { + mem_fetch *mf = m_L1T->next_access(); + m_next_wb = mf->get_inst(); + delete mf; + } + break; + case 2: // const cache response + if( m_L1C->access_ready() ) { + mem_fetch *mf = m_L1C->next_access(); + m_next_wb = mf->get_inst(); delete mf; } + break; + case 3: // global/local + if( m_next_global ) { + m_next_wb = m_next_global->get_inst(); + if( m_next_global->isatomic() ) + m_core->decrement_atomic_count(m_next_global->get_wid(),m_next_wb.active_count()); + delete m_next_global; + m_next_global = NULL; + } + break; + default: abort(); } } } @@ -1339,6 +947,34 @@ void ldst_unit::cycle() if( m_pipeline_reg[stage]->empty() && !m_pipeline_reg[stage+1]->empty() ) move_warp(m_pipeline_reg[stage], m_pipeline_reg[stage+1]); + if( !m_response_fifo.empty() ) { + mem_fetch *mf = m_response_fifo.front(); + if (mf->istexture()) { + mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L1T->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_response_fifo.pop_front(); + } else if (mf->isconst()) { + mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L1C->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_response_fifo.pop_front(); + } else { + if( mf->get_is_write() ) { + m_core->store_ack(mf); + m_response_fifo.pop_front(); + delete mf; + } else { + if( m_next_global == NULL ) { + mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); + m_response_fifo.pop_front(); + m_next_global = mf; + } + } + } + } + + m_L1T->cycle(); + m_L1C->cycle(); + // process new memory requests warp_inst_t &pipe_reg = *m_dispatch_reg; generate_mem_accesses(pipe_reg); @@ -1556,7 +1192,8 @@ void ldst_unit::print(FILE *fout) const } fprintf(fout,"\n"); } - m_mshr_unit->print(fout); + fprintf(fout,"LD/ST wb = "); + m_next_wb.print(fout); fprintf(fout,"Pending register writes:\n"); std::map<unsigned/*warp_id*/, std::map<unsigned/*regnum*/,unsigned/*count*/> >::const_iterator w; for( w=m_pending_writes.begin(); w!=m_pending_writes.end(); w++ ) { @@ -1571,6 +1208,8 @@ void ldst_unit::print(FILE *fout) const } fprintf(fout,"\n"); } + m_L1C->display_state(fout); + m_L1T->display_state(fout); } void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) @@ -1583,6 +1222,8 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) dump_istream_state(fout); fprintf(fout,"\n"); + m_L1I->display_state(fout); + fprintf(fout, "IF/ID = "); if( !m_inst_fetch_buffer.m_valid ) fprintf(fout,"bubble\n"); @@ -1691,10 +1332,6 @@ void shader_core_ctx::cache_flush() m_ldst_unit->flush(); } -static int *_inmatch; -static int *_outmatch; -static int **_request; - // modifiers std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() { @@ -1707,14 +1344,6 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() int _square = ( _inputs > _outputs ) ? _inputs : _outputs; int _pri = (int)m_last_cu; - if( _inmatch == NULL ) { - _inmatch = new int[ _inputs ]; - _outmatch = new int[ _outputs ]; - _request = new int*[ _inputs ]; - for(int i=0; i<_inputs;i++) - _request[i] = new int[_outputs]; - } - // Clear matching for ( int i = 0; i < _inputs; ++i ) _inmatch[i] = -1; @@ -1749,14 +1378,14 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() // Step through the current diagonal for ( input = 0; input < _inputs; ++input ) { + assert( input < _inputs ); + assert( output < _outputs ); if ( ( output < _outputs ) && ( _inmatch[input] == -1 ) && ( _outmatch[output] == -1 ) && ( _request[input][output]/*.label != -1*/ ) ) { // Grant! - assert( input < _inputs ); _inmatch[input] = output; - assert( output < _outputs ); _outmatch[output] = input; } @@ -1953,9 +1582,8 @@ bool shader_core_ctx::fetch_unit_response_buffer_full() const void shader_core_ctx::accept_fetch_response( mem_fetch *mf ) { - m_L1I->fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle); - m_warp[mf->get_wid()].clear_imiss_pending(); - delete mf; + mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L1I->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); } bool shader_core_ctx::ldst_unit_response_buffer_full() @@ -1966,7 +1594,6 @@ bool shader_core_ctx::ldst_unit_response_buffer_full() void shader_core_ctx::accept_ldst_unit_response(mem_fetch * mf) { m_ldst_unit->fill(mf); - //freed_read_mfs++; } void shader_core_ctx::store_ack( class mem_fetch *mf ) @@ -2076,39 +1703,6 @@ 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_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 = space.is_local(); - m_isconst = space.is_const(); - m_istexture = space==tex_space; - m_isatomic = false; - m_insts.clear(); - m_warp_id = warp_id; -} - -void mshr_entry::print(FILE *fp) const -{ - 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), - m_mf?MSHR_Status_str[ m_mf->get_status() ]:"???"); - if ( m_mf ) - ptx_print_insn( m_mf->get_pc(), fp ); - fprintf(fp,"\n"); -} - void opndcoll_rfu_t::add_port( unsigned num_collector_units, warp_inst_t **input_port, warp_inst_t **output_port ) @@ -2368,14 +1962,12 @@ void simt_core_cluster::cache_flush() m_core[i]->cache_flush(); } -bool simt_core_cluster::icnt_injection_buffer_full(new_addr_type addr, int bsize, bool write ) +bool simt_core_cluster::icnt_injection_buffer_full(unsigned size, bool write) { - //requests should be single always now - int rsize = bsize; - //maintain similar functionality with fq_push, if its a read, bsize is the load size, not the request's size + unsigned request_size = size; if (!write) - rsize = READ_PACKET_SIZE; - return ! ::icnt_has_buffer(m_cluster_id, rsize); + request_size = READ_PACKET_SIZE; + return ! ::icnt_has_buffer(m_cluster_id, request_size); } void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) @@ -2395,7 +1987,7 @@ void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) } unsigned destination = mf->get_tlx_addr().chip; - mf->set_status(IN_ICNT2MEM,MR_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle); + mf->set_status(IN_ICNT_TO_MEM,gpu_sim_cycle+gpu_tot_sim_cycle); if (!mf->get_is_write()) { mf->set_type(RD_REQ); ::icnt_push(m_cluster_id, m_config->mem2device(destination), (void*)mf, mf->get_ctrl_size() ); @@ -2406,12 +1998,6 @@ void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) } } -void simt_core_cluster::icnt_eject_response_packet(class mem_fetch * mf) -{ - assert( mf->get_tpc() == m_cluster_id ); - m_response_fifo.push_back(mf); -} - void simt_core_cluster::icnt_cycle() { if( !m_response_fifo.empty() ) { @@ -2437,13 +2023,13 @@ void simt_core_cluster::icnt_cycle() return; assert(mf->get_tpc() == m_cluster_id); assert(mf->get_type() == REPLY_DATA); - mf->set_status(IN_CLUSTER2SHADER,MR_2SH_FQ_POP,gpu_sim_cycle+gpu_tot_sim_cycle); + mf->set_status(IN_CLUSTER_TO_SHADER_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); //m_memory_stats->memlatstat_read_done(mf,m_shader_config->max_warps_per_shader); m_response_fifo.push_back(mf); } } -void simt_core_cluster::mem_instruction_stats(class warp_inst_t &inst) +void simt_core_cluster::mem_instruction_stats(const class warp_inst_t &inst) { m_gpu->mem_instruction_stats(inst); } diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index 786913a..0d74e95 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -64,6 +64,9 @@ * Vancouver, BC V6T 1Z4 */ +#ifndef SHADER_H +#define SHADER_H + #include <stdio.h> #include <stdlib.h> #include <math.h> @@ -80,7 +83,6 @@ #include "../cuda-sim/ptx.tab.h" #include "../cuda-sim/dram_callback.h" -#include "gpu-cache.h" #include "delayqueue.h" #include "stack.h" #include "dram.h" @@ -88,9 +90,7 @@ #include "scoreboard.h" #include "mem_fetch.h" #include "stats.h" - -#ifndef SHADER_H -#define SHADER_H +#include "gpu-cache.h" #define NO_OP_FLAG 0xFF @@ -298,102 +298,6 @@ private: unsigned long long *m_branch_div_cycle; }; - -class mshr_entry { -public: - mshr_entry() - { - m_merged_requests=NULL; - m_mf=NULL; - m_id=0; - m_status = INITIALIZED; - m_isatomic=false; - } - void set_id( unsigned n ) { m_id = n; } - unsigned get_id() const { return m_id; } - 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; } - class mem_fetch *get_mf() { return m_mf; } - void add_inst( warp_inst_t inst ) - { - m_insts.push_back(inst); - m_isatomic = inst.isatomic(); - } - void merge( mshr_entry *mshr ) - { - //merge this request; - m_merged_requests = mshr; - mshr->m_merged_on_other_reqest = true; - } - void set_fetched() - { - mshr_entry *mshr = this; - while( mshr ) { - mshr->m_status=FETCHED; - mshr->m_mf=NULL; - mshr=mshr->m_merged_requests; - } - } - mshr_entry *get_last_merged() - { - 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::list<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; - } - } - - 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(n<m_insts.size()); - return m_insts[n]; - } - bool isatomic() const { return m_isatomic; } - new_addr_type get_addr() const { return m_addr; } - void print(FILE *fp) const; - -private: - unsigned m_id; - unsigned m_request_uid; - unsigned m_warp_id; - new_addr_type m_addr; // address being fetched - std::vector<warp_inst_t> m_insts; - bool m_iswrite; - bool m_merged_on_other_reqest; //true if waiting for another mshr - this mshr doesn't send a memory request - struct mshr_entry *m_merged_requests; //mshrs waiting on this mshr - class mem_fetch *m_mf; // link to corresponding memory fetch structure - enum mshr_status m_status; - 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. - bool m_isatomic; -}; - const unsigned WARP_PER_CTA_MAX = 32; typedef std::bitset<WARP_PER_CTA_MAX> warp_set_t; @@ -556,11 +460,19 @@ private: m_queue=NULL; m_allocated_bank=NULL; m_allocator_rr_head=NULL; + _inmatch=NULL; + _outmatch=NULL; + _request=NULL; } void init( unsigned num_cu, unsigned num_banks ) { m_num_collectors = num_cu; m_num_banks = num_banks; + _inmatch = new int[ m_num_banks ]; + _outmatch = new int[ m_num_collectors ]; + _request = new int*[ m_num_banks ]; + for(unsigned i=0; i<m_num_banks;i++) + _request[i] = new int[m_num_collectors]; m_queue = new std::list<op_t>[num_banks]; m_allocated_bank = new allocation_t[num_banks]; m_allocator_rr_head = new unsigned[num_cu]; @@ -634,6 +546,10 @@ private: unsigned *m_allocator_rr_head; // cu # -> next bank to check for request (rr-arb) unsigned m_last_cu; // first cu to check while arb-ing banks (rr) + + int *_inmatch; + int *_outmatch; + int **_request; }; class collector_unit_t { @@ -786,63 +702,6 @@ private: warp_set_t m_warp_at_barrier; }; -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) const { return (num <= m_free_list.size()); } - - mshr_entry* return_head(); - - //return queue pop; (includes texture pipeline return) - void pop_return_head(); - - mshr_entry* add_mshr(mem_access_t &access, warp_inst_t* inst); - void mshr_return_from_mem(unsigned mshr_id); - unsigned get_max_mshr_used() const {return m_max_mshr_used;} - void print(FILE* fp); - -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::list<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::list<mshr_entry*> m_free_list; - std::list<mshr_entry*> m_mshr_return_queue; - std::list<mshr_entry*> m_texture_mshr_pipeline; - unsigned m_max_mshr_used; - mshr_lookup m_mshr_lookup; -}; - struct insn_latency_info { unsigned pc; unsigned long latency; @@ -865,6 +724,8 @@ struct ifetch_buffer_t { unsigned m_warp_id; }; +class shader_core_config; + class simd_function_unit { public: simd_function_unit( const shader_core_config *config ); @@ -966,10 +827,12 @@ public: }; class simt_core_cluster; +class shader_memory_interface; +class cache_t; class ldst_unit: public pipelined_simd_unit { public: - ldst_unit( simt_core_cluster *cluster, + ldst_unit( shader_memory_interface *icnt, shader_core_ctx *core, opndcoll_rfu_t *operand_collector, Scoreboard *scoreboard, @@ -1001,41 +864,33 @@ public: private: void generate_mem_accesses(warp_inst_t &pipe_reg); - void tex_cache_access(warp_inst_t &inst); - void const_cache_access(warp_inst_t &inst); bool shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); bool constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); bool texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); bool memory_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); - mem_stage_stall_type ccache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;} - mem_stage_stall_type tcache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;} - mem_stage_stall_type dcache_check(warp_inst_t &inst, mem_access_t& access); - - typedef mem_stage_stall_type (ldst_unit::*cache_check_t)(warp_inst_t &,mem_access_t&); - - mem_stage_stall_type process_memory_access_queue( ldst_unit::cache_check_t cache_check, - unsigned ports_per_bank, - unsigned memory_send_max, - warp_inst_t &inst ); - mem_stage_stall_type send_mem_request(warp_inst_t &inst, mem_access_t &access); + mem_stage_stall_type process_memory_access_queue( cache_t *cache, warp_inst_t &inst ); + mem_fetch *create_data_mem_fetch(warp_inst_t &inst, mem_access_t &access); const memory_config *m_memory_config; - class simt_core_cluster *m_cluster; + class shader_memory_interface *m_icnt; class shader_core_ctx *m_core; unsigned m_sid; unsigned m_tpc; - cache_t *m_L1D; // data cache (global/local memory accesses) cache_t *m_L1T; // texture cache cache_t *m_L1C; // constant cache - mshr_shader_unit *m_mshr_unit; std::map<unsigned/*warp_id*/, std::map<unsigned/*regnum*/,unsigned/*count*/> > m_pending_writes; std::list<mem_fetch*> m_response_fifo; opndcoll_rfu_t *m_operand_collector; Scoreboard *m_scoreboard; + mem_fetch *m_next_global; + warp_inst_t m_next_wb; + unsigned m_writeback_arb; // round-robin arbiter for writeback contention between L1T, L1C, shared + unsigned m_num_writeback_clients; + enum mem_stage_stall_type m_mem_rc; shader_core_stats *m_stats; @@ -1065,8 +920,6 @@ struct shader_core_config : public core_config m_L1I_config.init(); m_L1T_config.init(); m_L1C_config.init(); - m_L1D_config.init(); - gpgpu_cache_dl1_linesize = m_L1D_config.get_line_sz(); gpgpu_cache_texl1_linesize = m_L1T_config.get_line_sz(); gpgpu_cache_constl1_linesize = m_L1C_config.get_line_sz(); @@ -1083,7 +936,6 @@ struct shader_core_config : public core_config cache_config m_L1I_config; cache_config m_L1T_config; cache_config m_L1C_config; - cache_config m_L1D_config; unsigned n_mshr_per_shader; bool gpgpu_dwf_reg_bankconflict; @@ -1095,10 +947,7 @@ struct shader_core_config : public core_config unsigned gpgpu_shmem_size; unsigned gpgpu_shader_registers; int gpgpu_warpdistro_shader; - int gpgpu_interwarp_mshr_merge; int gpgpu_shmem_port_per_bank; - int gpgpu_cache_port_per_bank; - int gpgpu_const_port_per_bank; 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 @@ -1213,6 +1062,9 @@ private: // thread contexts thread_ctx_t *m_thread; // functional state, per thread fetch state + // interconnect interface + shader_memory_interface *m_icnt; + // fetch cache_t *m_L1I; // instruction cache int m_last_warp_fetched; @@ -1255,11 +1107,9 @@ public: void issue_block2core( class kernel_info_t &kernel ); void cache_flush(); - bool icnt_injection_buffer_full(new_addr_type addr, int bsize, bool write ); + bool icnt_injection_buffer_full(unsigned size, bool write); void icnt_inject_request_packet(class mem_fetch *mf); - bool icnt_ejection_buffer_full() const { return m_response_fifo.size() >= m_config->n_simt_ejection_buffer_size; } - void icnt_eject_response_packet(class mem_fetch * mf); - void mem_instruction_stats(class warp_inst_t &inst); + void mem_instruction_stats(const class warp_inst_t &inst); void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc ); gpgpu_sim *get_gpu() { return m_gpu; } @@ -1280,4 +1130,21 @@ private: std::list<mem_fetch*> m_response_fifo; }; +class shader_memory_interface : public mem_fetch_interface { +public: + shader_memory_interface( simt_core_cluster *port ) { m_port=port; } + virtual bool full( unsigned size, bool write ) const + { + return m_port->icnt_injection_buffer_full(size,write); + } + virtual void push(mem_fetch *mf) + { + if( !mf->get_inst().empty() ) + m_port->mem_instruction_stats(mf->get_inst()); // not I$-fetch + m_port->icnt_inject_request_packet(mf); + } +private: + simt_core_cluster *m_port; +}; + #endif /* SHADER_H */ diff --git a/src/gpgpu-sim/stat-tool.h b/src/gpgpu-sim/stat-tool.h index ebac6c2..00b7771 100644 --- a/src/gpgpu-sim/stat-tool.h +++ b/src/gpgpu-sim/stat-tool.h @@ -68,29 +68,11 @@ #include "../abstract_hardware_model.h" #include "histogram.h" +#include "../tr1_hash_map.h" #include <stdio.h> #include <zlib.h> -// detect gcc 4.3 and use unordered map (part of c++0x) -// unordered map doesn't play nice with _GLIBCXX_DEBUG, just use a map if its enabled. -#if defined( __GNUC__ ) and not defined( _GLIBCXX_DEBUG ) -#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 - #include <unordered_map> - #define my_hash_map std::unordered_map -#else - #include <ext/hash_map> - namespace std { - using namespace __gnu_cxx; - } - #define my_hash_map std::hash_map -#endif -#else - #include <map> - #define my_hash_map std::map - #define USE_MAP -#endif - ///////////////////////////////////////////////////////////////////////////////////// // logger snapshot trigger: // - automate the snap_shot part of loggers to avoid modifying simulation loop everytime diff --git a/src/gpgpu-sim/stats.h b/src/gpgpu-sim/stats.h index 8115eae..0abdb22 100644 --- a/src/gpgpu-sim/stats.h +++ b/src/gpgpu-sim/stats.h @@ -102,7 +102,6 @@ struct shader_core_stats 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; diff --git a/src/gpgpu-sim/visualizer.cc b/src/gpgpu-sim/visualizer.cc index 440f9e0..51348d5 100644 --- a/src/gpgpu-sim/visualizer.cc +++ b/src/gpgpu-sim/visualizer.cc @@ -259,7 +259,7 @@ public: void update_ld(unsigned int uid,unsigned int slot, long int time) { if ( ld_time_map.find( uid )!=ld_time_map.end() ) { ld_time_map[uid][slot]=time; - } else if (slot <= MR_2SH_FQ_POP ) { + } else if (slot < NUM_MEM_REQ_STAT ) { std::vector<long int> time_vec; time_vec.resize(ld_vector_size); time_vec[slot] = time; @@ -280,15 +280,15 @@ public: } void check_ld_update(unsigned int uid,unsigned int slot, long int latency) { if ( ld_time_map.find( uid )!=ld_time_map.end() ) { - int our_latency = ld_time_map[uid][slot] - ld_time_map[uid][MR_ICNT_PUSHED]; + int our_latency = ld_time_map[uid][slot] - ld_time_map[uid][IN_ICNT_TO_MEM]; assert( our_latency == latency); - } else if (slot <= MR_2SH_FQ_POP ) { + } else if (slot < NUM_MEM_REQ_STAT ) { abort(); } } void check_st_update(unsigned int uid,unsigned int slot, long int latency) { if ( st_time_map.find( uid )!=st_time_map.end() ) { - int our_latency = st_time_map[uid][slot] - st_time_map[uid][MR_ICNT_PUSHED]; + int our_latency = st_time_map[uid][slot] - st_time_map[uid][IN_ICNT_TO_MEM]; assert( our_latency == latency); } else { abort(); @@ -306,7 +306,7 @@ private: while (iter != ld_time_map.end()) { last_update=0; first=-1; - if (!iter->second[MR_WRITEBACK]) { + if (!iter->second[IN_SHADER_FETCHED]) { //this request is not done yet skip it! ++iter; continue; @@ -351,7 +351,7 @@ private: while ( iter != st_time_map.end() ) { last_update=0; first=-1; - if (!iter->second[MR_2SH_ICNT_PUSHED]) { + if (!iter->second[IN_SHADER_FETCHED]) { //this request is not done yet skip it! ++iter; continue; @@ -465,8 +465,8 @@ public: my_time_vector* g_my_time_vector; -void time_vector_create(int ld_size,int st_size) { - g_my_time_vector = new my_time_vector(ld_size,st_size); +void time_vector_create(int size) { + g_my_time_vector = new my_time_vector(size,size); } diff --git a/src/gpgpu-sim/visualizer.h b/src/gpgpu-sim/visualizer.h index 0d9424a..8c74d53 100644 --- a/src/gpgpu-sim/visualizer.h +++ b/src/gpgpu-sim/visualizer.h @@ -67,7 +67,7 @@ void visualizer_options(class OptionParser *opp); 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_create(int size); void time_vector_print(void); void time_vector_update(unsigned int uid,int slot ,long int cycle,int type); void check_time_vector_update(unsigned int uid,int slot ,long int latency,int type); diff --git a/src/intersim/interconnect_interface.cpp b/src/intersim/interconnect_interface.cpp index 1b4ffea..b838dcf 100644 --- a/src/intersim/interconnect_interface.cpp +++ b/src/intersim/interconnect_interface.cpp @@ -17,9 +17,8 @@ #include "injection.hpp" #include "interconnect_interface.h" #include "../gpgpu-sim/mem_fetch.h" -#include "../gpgpu-sim/gpu-sim.h" -#include "../gpgpu-sim/shader.h" #include <string.h> +#include <math.h> int _flit_size ; @@ -317,6 +316,9 @@ bool interconnect_has_buffer(unsigned int input_node, unsigned int tot_req_size) return has_buffer; } +extern unsigned long long gpu_sim_cycle; +extern unsigned long long gpu_tot_sim_cycle; + void interconnect_push ( unsigned int input_node, unsigned int output_node, void* data, unsigned int size) { @@ -465,14 +467,9 @@ void init_interconnect (char* config_file, if (icnt_config.GetInt("input_buf_size")) { input_buffer_capacity = icnt_config.GetInt("input_buf_size"); } else { - if (shader_config->m_L1D_config.get_num_lines() && !shader_config->gpgpu_no_dl1) { - int l1cache_linesize = shader_config->m_L1D_config.get_line_sz(); - input_buffer_capacity = shader_config->n_thread_per_shader*(l1cache_linesize/_flit_size+(int)ceil(8.0f/_flit_size)); - } else { - input_buffer_capacity = shader_config->n_thread_per_shader*((int)ceil(8.0f/_flit_size)); - } + input_buffer_capacity = 8; } - create_buf(traffic[0]->_dests,shader_config->warp_size,icnt_config.GetInt( "num_vcs" )); + create_buf(traffic[0]->_dests,input_buffer_capacity,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"); diff --git a/src/tr1_hash_map.h b/src/tr1_hash_map.h index 1ff7c8e..f7813ae 100644 --- a/src/tr1_hash_map.h +++ b/src/tr1_hash_map.h @@ -3,20 +3,38 @@ // detection and fallback for unordered_map in C++0x #ifdef __cplusplus #ifdef __GNUC__ - #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 - #include <unordered_map> - #define tr1_hash_map std::unordered_map - #define tr1_hash_map_ismap 0 + #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 + #include <unordered_map> + #define tr1_hash_map std::unordered_map + #define tr1_hash_map_ismap 0 + #else + #include <map> + #define tr1_hash_map std::map + #define tr1_hash_map_ismap 1 + #endif #else #include <map> #define tr1_hash_map std::map #define tr1_hash_map_ismap 1 #endif - #else - #include <map> - #define tr1_hash_map std::map - #define tr1_hash_map_ismap 1 - #endif -#endif + // detect gcc 4.3 and use unordered map (part of c++0x) + // unordered map doesn't play nice with _GLIBCXX_DEBUG, just use a map if its enabled. + #if defined( __GNUC__ ) and not defined( _GLIBCXX_DEBUG ) + #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 + #include <unordered_map> + #define my_hash_map std::unordered_map + #else + #include <ext/hash_map> + namespace std { + using namespace __gnu_cxx; + } + #define my_hash_map std::hash_map + #endif + #else + #include <map> + #define my_hash_map std::map + #define USE_MAP + #endif +#endif |
