diff options
Diffstat (limited to 'src/gpgpu-sim')
30 files changed, 5912 insertions, 6722 deletions
diff --git a/src/gpgpu-sim/Makefile b/src/gpgpu-sim/Makefile index 96b1a5c..5451736 100644 --- a/src/gpgpu-sim/Makefile +++ b/src/gpgpu-sim/Makefile @@ -78,8 +78,8 @@ endif ifneq ($(DEBUG),1) OPTFLAGS += -O3 else - CXXFLAGS_L2CACHE += -DGLIBCXX_DEBUG_PEDANTIC - CXXFLAGS += -D_GLIBCXX_DEBUG -DGLIBCXX_DEBUG_PEDANTIC + CXXFLAGS_L2CACHE += + CXXFLAGS += endif OPTFLAGS += -g3 -fPIC @@ -127,7 +127,7 @@ addrdec.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h addrdec.o: /usr/include/bits/select.h /usr/include/bits/sigset.h addrdec.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h addrdec.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h -addrdec.o: /usr/include/assert.h ../option_parser.h +addrdec.o: /usr/include/assert.h ../option_parser.h gpu-sim.h delayqueue.o: delayqueue.h /usr/include/stdio.h /usr/include/features.h delayqueue.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h delayqueue.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h @@ -141,12 +141,14 @@ delayqueue.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h delayqueue.o: /usr/include/sys/select.h /usr/include/bits/select.h delayqueue.o: /usr/include/bits/sigset.h /usr/include/bits/time.h delayqueue.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h -delayqueue.o: /usr/include/alloca.h gpu-misc.h ../intersim/statwraper.h -dram.o: gpu-misc.h dram.h /usr/include/stdio.h /usr/include/features.h -dram.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h -dram.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h -dram.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h -dram.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h +delayqueue.o: /usr/include/alloca.h gpu-misc.h gpu-sim.h +delayqueue.o: ../intersim/statwraper.h +dram.o: gpu-sim.h gpu-misc.h dram.h /usr/include/stdio.h +dram.o: /usr/include/features.h /usr/include/sys/cdefs.h +dram.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +dram.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h +dram.o: /usr/include/bits/typesizes.h /usr/include/libio.h +dram.o: /usr/include/_G_config.h /usr/include/wchar.h dram.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h dram.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h dram.o: /usr/include/endian.h /usr/include/bits/endian.h @@ -154,7 +156,7 @@ dram.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h dram.o: /usr/include/bits/select.h /usr/include/bits/sigset.h dram.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h dram.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h delayqueue.h -dram.o: /usr/include/assert.h ../cuda-sim/dram_callback.h +dram.o: /usr/include/assert.h ../cuda-sim/dram_callback.h mem_latency_stat.h dram_sched.o: dram_sched.h dram.h /usr/include/stdio.h dram_sched.o: /usr/include/features.h /usr/include/sys/cdefs.h dram_sched.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h @@ -171,14 +173,9 @@ dram_sched.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h dram_sched.o: /usr/include/alloca.h delayqueue.h /usr/include/assert.h dram_sched.o: ../cuda-sim/dram_callback.h shader.h /usr/include/math.h dram_sched.o: /usr/include/bits/huge_val.h /usr/include/bits/mathdef.h -dram_sched.o: /usr/include/bits/mathcalls.h /usr/include/limits.h -dram_sched.o: /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h -dram_sched.o: /usr/include/linux/limits.h /usr/include/bits/posix2_lim.h -dram_sched.o: ../cuda-sim/ptx.tab.h gpu-cache.h ../abstract_hardware_model.h -dram_sched.o: stack.h gpu-sim.h /usr/include/zlib.h /usr/include/zconf.h -dram_sched.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h -dram_sched.o: /usr/include/bits/confname.h /usr/include/getopt.h -dram_sched.o: ../option_parser.h mem_fetch.h addrdec.h gpu-misc.h +dram_sched.o: /usr/include/bits/mathcalls.h ../cuda-sim/ptx.tab.h gpu-cache.h +dram_sched.o: ../abstract_hardware_model.h stack.h scoreboard.h gpu-sim.h +dram_sched.o: gpu-misc.h mem_latency_stat.h dwf.o: dwf.h ../abstract_hardware_model.h histogram.h /usr/include/string.h dwf.o: /usr/include/features.h /usr/include/sys/cdefs.h dwf.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h @@ -197,7 +194,10 @@ gpu-cache.o: /usr/include/bits/select.h /usr/include/bits/sigset.h gpu-cache.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h gpu-cache.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h gpu-cache.o: ../abstract_hardware_model.h gpu-misc.h addrdec.h -gpu-cache.o: /usr/include/assert.h ../option_parser.h /usr/include/string.h +gpu-cache.o: /usr/include/assert.h ../option_parser.h stat-tool.h +gpu-cache.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h +gpu-cache.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h +gpu-cache.o: /usr/include/getopt.h gpu-sim.h /usr/include/string.h gpu-misc.o: gpu-misc.h gpu-sim.o: gpu-sim.h /usr/include/stdio.h /usr/include/features.h gpu-sim.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h @@ -216,15 +216,15 @@ gpu-sim.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h gpu-sim.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h gpu-sim.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h gpu-sim.o: /usr/include/getopt.h ../option_parser.h shader.h -gpu-sim.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h -gpu-sim.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h -gpu-sim.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h -gpu-sim.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h +gpu-sim.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h +gpu-sim.o: ../cuda-sim/dram_callback.h gpu-cache.h gpu-sim.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h -gpu-sim.o: mem_fetch.h addrdec.h gpu-misc.h icnt_wrapper.h dwf.h -gpu-sim.o: warp_tracker.h cflogger.h l2cache.h ../cuda-sim/ptx-stats.h +gpu-sim.o: scoreboard.h mem_fetch.h addrdec.h gpu-misc.h icnt_wrapper.h dwf.h +gpu-sim.o: warp_tracker.h stat-tool.h l2cache.h ../cuda-sim/ptx-stats.h gpu-sim.o: ../intersim/statwraper.h ../debug.h ../abstract_hardware_model.h -gpu-sim.o: /usr/include/string.h mem_latency_stat.h +gpu-sim.o: ../gpgpusim_entrypoint.h ../cuda-sim/cuda-sim.h +gpu-sim.o: ../cuda-sim/dram_callback.h mem_latency_stat.h +gpu-sim.o: /usr/include/string.h icnt_wrapper.o: icnt_wrapper.h /usr/include/assert.h /usr/include/features.h icnt_wrapper.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h icnt_wrapper.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h @@ -239,7 +239,14 @@ icnt_wrapper.o: ../intersim/network.hpp ../intersim/credit.hpp icnt_wrapper.o: ../intersim/router.hpp ../intersim/buffer_state.hpp icnt_wrapper.o: ../intersim/stats.hpp ../intersim/traffic.hpp icnt_wrapper.o: ../intersim/routefunc.hpp ../intersim/outputset.hpp -icnt_wrapper.o: ../intersim/injection.hpp +icnt_wrapper.o: ../intersim/injection.hpp ../option_parser.h +icnt_wrapper.o: /usr/include/stdlib.h /usr/include/sys/types.h +icnt_wrapper.o: /usr/include/time.h /usr/include/endian.h +icnt_wrapper.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h +icnt_wrapper.o: /usr/include/sys/select.h /usr/include/bits/select.h +icnt_wrapper.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +icnt_wrapper.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +icnt_wrapper.o: /usr/include/alloca.h l2cache.o: /usr/include/stdlib.h /usr/include/features.h l2cache.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h l2cache.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h @@ -256,12 +263,58 @@ l2cache.o: /usr/include/bits/sys_errlist.h /usr/include/string.h l2cache.o: ../tr1_hash_map.h ../option_parser.h mem_fetch.h shader.h l2cache.o: /usr/include/math.h /usr/include/bits/huge_val.h l2cache.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h -l2cache.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h -l2cache.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h -l2cache.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h -l2cache.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h -l2cache.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h addrdec.h -l2cache.o: histogram.h l2cache.h ../intersim/statwraper.h +l2cache.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h +l2cache.o: ../cuda-sim/dram_callback.h gpu-cache.h +l2cache.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h +l2cache.o: scoreboard.h addrdec.h histogram.h l2cache.h +l2cache.o: ../intersim/statwraper.h gpu-sim.h +mem_latency_stat.o: ../abstract_hardware_model.h mem_latency_stat.h gpu-sim.h +mem_latency_stat.o: gpu-misc.h shader.h /usr/include/stdio.h +mem_latency_stat.o: /usr/include/features.h /usr/include/sys/cdefs.h +mem_latency_stat.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +mem_latency_stat.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h +mem_latency_stat.o: /usr/include/bits/typesizes.h /usr/include/libio.h +mem_latency_stat.o: /usr/include/_G_config.h /usr/include/wchar.h +mem_latency_stat.o: /usr/include/bits/stdio_lim.h +mem_latency_stat.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h +mem_latency_stat.o: /usr/include/sys/types.h /usr/include/time.h +mem_latency_stat.o: /usr/include/endian.h /usr/include/bits/endian.h +mem_latency_stat.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h +mem_latency_stat.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +mem_latency_stat.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +mem_latency_stat.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h +mem_latency_stat.o: /usr/include/math.h /usr/include/bits/huge_val.h +mem_latency_stat.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h +mem_latency_stat.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h +mem_latency_stat.o: ../cuda-sim/dram_callback.h gpu-cache.h delayqueue.h +mem_latency_stat.o: stack.h dram.h scoreboard.h mem_fetch.h addrdec.h +mem_latency_stat.o: ../option_parser.h stat-tool.h /usr/include/zlib.h +mem_latency_stat.o: /usr/include/zconf.h /usr/include/unistd.h +mem_latency_stat.o: /usr/include/bits/posix_opt.h +mem_latency_stat.o: /usr/include/bits/confname.h /usr/include/getopt.h +mem_latency_stat.o: ../cuda-sim/ptx-stats.h visualizer.h +mem_latency_stat.o: /usr/include/string.h +scoreboard.o: scoreboard.h /usr/include/stdio.h /usr/include/features.h +scoreboard.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +scoreboard.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h +scoreboard.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +scoreboard.o: /usr/include/libio.h /usr/include/_G_config.h +scoreboard.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h +scoreboard.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h +scoreboard.o: /usr/include/sys/types.h /usr/include/time.h +scoreboard.o: /usr/include/endian.h /usr/include/bits/endian.h +scoreboard.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h +scoreboard.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +scoreboard.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +scoreboard.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h +scoreboard.o: /usr/include/assert.h shader.h /usr/include/math.h +scoreboard.o: /usr/include/bits/huge_val.h /usr/include/bits/mathdef.h +scoreboard.o: /usr/include/bits/mathcalls.h ../cuda-sim/ptx.tab.h +scoreboard.o: ../cuda-sim/dram_callback.h gpu-cache.h +scoreboard.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h +scoreboard.o: ../cuda-sim/ptx_sim.h ../cuda-sim/dram_callback.h +scoreboard.o: ../tr1_hash_map.h ../cuda-sim/opcodes.h ../cuda-sim/opcodes.def +scoreboard.o: ../cuda-sim/memory.h /usr/include/string.h shader.o: shader.h /usr/include/stdio.h /usr/include/features.h shader.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h shader.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h @@ -276,18 +329,20 @@ shader.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h shader.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h shader.o: /usr/include/math.h /usr/include/bits/huge_val.h shader.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h +shader.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h +shader.o: ../cuda-sim/dram_callback.h gpu-cache.h +shader.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h +shader.o: scoreboard.h gpu-sim.h addrdec.h ../option_parser.h dwf.h +shader.o: warp_tracker.h stat-tool.h /usr/include/zlib.h /usr/include/zconf.h +shader.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +shader.o: /usr/include/bits/confname.h /usr/include/getopt.h gpu-misc.h +shader.o: ../cuda-sim/ptx_sim.h ../cuda-sim/dram_callback.h ../tr1_hash_map.h +shader.o: ../cuda-sim/opcodes.h ../cuda-sim/opcodes.def ../cuda-sim/memory.h +shader.o: /usr/include/string.h ../cuda-sim/ptx-stats.h +shader.o: ../cuda-sim/cuda-sim.h mem_fetch.h mem_latency_stat.h visualizer.h shader.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h shader.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h -shader.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h -shader.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h -shader.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h gpu-sim.h -shader.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h -shader.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h -shader.o: /usr/include/getopt.h ../option_parser.h mem_fetch.h addrdec.h -shader.o: dwf.h warp_tracker.h cflogger.h gpu-misc.h ../cuda-sim/ptx_sim.h -shader.o: ../cuda-sim/dram_callback.h ../cuda-sim/opcodes.h -shader.o: ../cuda-sim/opcodes.def ../cuda-sim/ptx-stats.h -shader.o: /usr/include/string.h +shader.o: /usr/include/bits/posix2_lim.h stack.o: stack.h ../abstract_hardware_model.h /usr/include/stdlib.h stack.o: /usr/include/features.h /usr/include/sys/cdefs.h stack.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h @@ -299,48 +354,46 @@ stack.o: /usr/include/bits/select.h /usr/include/bits/sigset.h stack.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h stack.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h stack.o: /usr/include/assert.h -stat-tool.o: /usr/include/stdio.h /usr/include/features.h -stat-tool.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h -stat-tool.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h -stat-tool.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h -stat-tool.o: /usr/include/libio.h /usr/include/_G_config.h -stat-tool.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h -stat-tool.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h +stat-tool.o: stat-tool.h ../abstract_hardware_model.h /usr/include/stdio.h +stat-tool.o: /usr/include/features.h /usr/include/sys/cdefs.h +stat-tool.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +stat-tool.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h +stat-tool.o: /usr/include/bits/typesizes.h /usr/include/libio.h +stat-tool.o: /usr/include/_G_config.h /usr/include/wchar.h +stat-tool.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h +stat-tool.o: /usr/include/zlib.h /usr/include/zconf.h stat-tool.o: /usr/include/sys/types.h /usr/include/time.h stat-tool.o: /usr/include/endian.h /usr/include/bits/endian.h stat-tool.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h stat-tool.o: /usr/include/bits/select.h /usr/include/bits/sigset.h stat-tool.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h -stat-tool.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h -stat-tool.o: /usr/include/assert.h /usr/include/zlib.h /usr/include/zconf.h -stat-tool.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h -stat-tool.o: /usr/include/bits/confname.h /usr/include/getopt.h histogram.h -stat-tool.o: ../abstract_hardware_model.h cflogger.h -visualizer.o: gpu-sim.h /usr/include/stdio.h /usr/include/features.h +stat-tool.o: /usr/include/bits/pthreadtypes.h /usr/include/unistd.h +stat-tool.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h +stat-tool.o: /usr/include/getopt.h /usr/include/stdlib.h +stat-tool.o: /usr/include/alloca.h /usr/include/assert.h histogram.h +visualizer.o: visualizer.h /usr/include/stdio.h /usr/include/features.h visualizer.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h visualizer.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h visualizer.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h visualizer.o: /usr/include/libio.h /usr/include/_G_config.h visualizer.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h -visualizer.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h -visualizer.o: /usr/include/sys/types.h /usr/include/time.h -visualizer.o: /usr/include/endian.h /usr/include/bits/endian.h -visualizer.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h -visualizer.o: /usr/include/bits/select.h /usr/include/bits/sigset.h -visualizer.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h -visualizer.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h -visualizer.o: /usr/include/math.h /usr/include/bits/huge_val.h +visualizer.o: /usr/include/bits/sys_errlist.h /usr/include/zlib.h +visualizer.o: /usr/include/zconf.h /usr/include/sys/types.h +visualizer.o: /usr/include/time.h /usr/include/endian.h +visualizer.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h +visualizer.o: /usr/include/sys/select.h /usr/include/bits/select.h +visualizer.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +visualizer.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +visualizer.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +visualizer.o: /usr/include/bits/confname.h /usr/include/getopt.h gpu-sim.h +visualizer.o: l2cache.h dram.h /usr/include/stdlib.h /usr/include/alloca.h +visualizer.o: delayqueue.h /usr/include/assert.h ../cuda-sim/dram_callback.h +visualizer.o: shader.h /usr/include/math.h /usr/include/bits/huge_val.h visualizer.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h -visualizer.o: /usr/include/zlib.h /usr/include/zconf.h /usr/include/unistd.h -visualizer.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h -visualizer.o: /usr/include/getopt.h ../option_parser.h shader.h -visualizer.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h -visualizer.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h -visualizer.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h -visualizer.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h -visualizer.o: ../abstract_hardware_model.h delayqueue.h stack.h dram.h -visualizer.o: mem_fetch.h addrdec.h /usr/include/string.h -visualizer.o: ../gpgpu-sim/shader.h ../gpgpu-sim/mem_fetch.h +visualizer.o: ../cuda-sim/ptx.tab.h gpu-cache.h ../abstract_hardware_model.h +visualizer.o: stack.h scoreboard.h ../option_parser.h mem_latency_stat.h +visualizer.o: stat-tool.h /usr/include/string.h ../gpgpu-sim/shader.h +visualizer.o: ../gpgpu-sim/mem_fetch.h addrdec.h warp_tracker.o: warp_tracker.h ../abstract_hardware_model.h shader.h warp_tracker.o: /usr/include/stdio.h /usr/include/features.h warp_tracker.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h @@ -357,8 +410,6 @@ warp_tracker.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h warp_tracker.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h warp_tracker.o: /usr/include/math.h /usr/include/bits/huge_val.h warp_tracker.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h -warp_tracker.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h -warp_tracker.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h -warp_tracker.o: /usr/include/bits/posix2_lim.h /usr/include/assert.h -warp_tracker.o: ../cuda-sim/ptx.tab.h ../cuda-sim/dram_callback.h gpu-cache.h -warp_tracker.o: delayqueue.h stack.h dram.h +warp_tracker.o: /usr/include/assert.h ../cuda-sim/ptx.tab.h +warp_tracker.o: ../cuda-sim/dram_callback.h gpu-cache.h delayqueue.h stack.h +warp_tracker.o: dram.h scoreboard.h gpu-sim.h diff --git a/src/gpgpu-sim/delayqueue.cc b/src/gpgpu-sim/delayqueue.cc deleted file mode 100644 index 659018b..0000000 --- a/src/gpgpu-sim/delayqueue.cc +++ /dev/null @@ -1,467 +0,0 @@ -/* - * delayqueue.c - * - * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda, - * Ivan Sham, Henry Tran and the University of British Columbia - * Vancouver, BC V6T 1Z4 - * All Rights Reserved. - * - * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE - * TERMS AND CONDITIONS. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h - * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda - * (property of NVIDIA). The files benchmarks/BlackScholes/ and - * benchmarks/template/ are derived from the CUDA SDK available from - * http://www.nvidia.com/cuda (also property of NVIDIA). The files from - * src/intersim/ are derived from Booksim (a simulator provided with the - * textbook "Principles and Practices of Interconnection Networks" available - * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by - * the corresponding legal terms and conditions set forth separately (original - * copyright notices are left in files from these sources and where we have - * modified a file our copyright notice appears before the original copyright - * notice). - * - * Using this version of GPGPU-Sim requires a complete installation of CUDA - * which is distributed seperately by NVIDIA under separate terms and - * conditions. To use this version of GPGPU-Sim with OpenCL requires a - * recent version of NVIDIA's drivers which support OpenCL. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the University of British Columbia nor the names of - * its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. - * - * 5. No nonprofit user may place any restrictions on the use of this software, - * including as modified by the user, by any other authorized user. - * - * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, - * Ali Bakhoda, George L. Yuan, at the University of British Columbia, - * Vancouver, BC V6T 1Z4 - */ - -#include "delayqueue.h" -#include "gpu-misc.h" -#include "gpu-sim.h" -#include "../intersim/statwraper.h" - -unsigned char dq_full( delay_queue* dq ) -{ - if (dq->max_len && dq->length >= dq->max_len) - return 1; - return 0; -} - -unsigned char dq_empty(delay_queue* dq ) -{ - return(dq->head == NULL)?1:0; -} - -unsigned int dq_n_element(delay_queue* dq ) -{ - return(dq->n_element); -} - -unsigned char dq_push(delay_queue* dq, void* data) { - if (dq->max_len) assert(dq->length < dq->max_len); - if (dq->head) { - if (dq->tail->data || dq->length < dq->min_len) { - dq->tail->next = (delay_data*) malloc(sizeof(delay_data)); - dq->tail = dq->tail->next; - dq->length++; - dq->n_element++; - } - } else { - dq->head = dq->tail = (delay_data*) malloc(sizeof(delay_data)); - dq->length++; - dq->n_element++; - } - dq->tail->next = NULL; - dq->tail->time_elapsed = dq->latency; - dq->tail->data = (void*)data; - dq->tail->push_time = gpu_sim_cycle; - return 1; -} - -void* dq_top(delay_queue* dq) { - if (dq->head) { - return dq->head->data; - } else { - return NULL; - } -} - -void* dq_pop(delay_queue* dq) { - delay_data* next; - void* data; - if (dq->head) { - if (dq->head->time_elapsed) { - dq->head->time_elapsed--; - data = NULL; - } else { - next = dq->head->next; - data = dq->head->data; - StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - dq->head->push_time)); - if ( dq->head == dq->tail ) { - assert( next == NULL ); - dq->tail = NULL; - } - free(dq->head); - dq->head = next; - dq->length--; - if (dq->length == 0) { - assert( dq->head == NULL ); - dq->tail = dq->head; - } - dq->n_element--; - } - if (dq->min_len && dq->length < dq->min_len) { - dq_push(dq,NULL); - dq->n_element--; // uncount NULL elements inserted to create delays - } - } else { - data = NULL; - } - return data; -} - -void dq_set_min_length(delay_queue* dq, unsigned int new_min_len) { - if (new_min_len == dq->min_len) return; - - if (new_min_len > dq->min_len) { - dq->min_len = new_min_len; - while (dq->length < dq->min_len) { - dq_push(dq,NULL); - dq->n_element--; // uncount NULL elements inserted to create delays - } - } else { - // in this branch imply that the original min_len is larger then 0 - // ie. dq->head != 0 - assert(dq->head); - dq->min_len = new_min_len; - while ((dq->length > dq->min_len) && (dq->tail->data == 0)) { - delay_data *iter; - iter = dq->head; - while (iter && (iter->next != dq->tail)) - iter = iter->next; - if (!iter) { - // there is only one node, and that node is empty - assert(dq->head->data == 0); - dq_pop(dq); - } else { - // there are more than one node, and tail node is empty - assert(iter->next == dq->tail); - free(dq->tail); - dq->tail = iter; - dq->tail->next = 0; - dq->length--; - } - } - } -} - -void dq_remove(void* data, delay_queue* dq) -{ - // removes an item from the queue without deallocating the memory - delay_data* ptr = NULL; - delay_data* temp = NULL; - - assert(dq); - assert(data); - - ptr = dq->head; - if (ptr) { - if (ptr->data == data) { - StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - ptr->push_time)); - dq->head = ptr->next; - if ( dq->head == NULL ) - dq->tail = NULL; - dq->length--; - return; - } - while (ptr->next) { - if (ptr->next->data == data) { - temp = ptr->next; - StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - temp->push_time)); - if ( ptr->next == dq->tail ) { - dq->tail = ptr; - } - ptr->next = ptr->next->next; - dq->length--; - return; - } - ptr = ptr->next; - } - } -} - -void removeEntry(void* data, delay_queue** dqq, int size_dq) -{ - int i; - delay_data* ptr = NULL; - delay_queue* dq = NULL; - delay_data* temp = NULL; - - assert(dqq); - assert(data); - - - for (i = 0; i<size_dq; i++) { - dq = dqq[i]; - ptr = dq->head; - if (ptr) { - if (ptr->data == data) { - dq->head = ptr->next; - if ( dq->head == NULL ) - dq->tail = NULL; - StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - ptr->push_time)); - free(ptr); - dq->length--; - return; - } - while (ptr->next) { - if (ptr->next->data == data) { - temp = ptr->next; - if ( ptr->next == dq->tail ) { - dq->tail = ptr; - } - ptr->next = ptr->next->next; - StatAddSample(dq->lat_stat, LOGB2 (gpu_sim_cycle - temp->push_time)); - free(temp); - dq->length--; - return; - } - ptr = ptr->next; - } - } - - } -} - -static int dq_uid_counter = 0; - -delay_queue* dq_create(const char* name, unsigned int latency, unsigned int min_len, unsigned int max_len) { - unsigned i; - delay_queue* dq; - dq = (delay_queue*) malloc(sizeof(delay_queue)); - dq->name = name; - dq->latency = latency; - dq->min_len = min_len; - dq->max_len = max_len; - dq->length = 0; - dq->n_element = 0; - dq->head = NULL; - dq->tail = NULL; - for (i=0;i<min_len;i++) dq_push(dq,NULL); - dq->uid = dq_uid_counter; - dq_uid_counter++; - if (1) { - dq->lat_stat = StatCreate(dq->name,1,32); - } - dq->max_size_stat = 0; - dq->avg_size_stat =0.0 ; - return dq; -} - -void dq_print(delay_queue* dq) { - delay_data* ddp = dq->head; - printf("%s(%d): ", dq->name, dq->length); - while (ddp) { - printf("%p ", ddp->data); - ddp = ddp->next; - } - printf("\n"); -} - -void dq_free(delay_queue* dq) { - while (dq->head) { - dq->tail = dq->head; - dq->head = dq->head->next; - free(dq->tail); - } - free(dq); - dq = NULL; -} - -void dq_update_stat(delay_queue* dq) { - if (dq->n_element > dq->max_size_stat) { - dq->max_size_stat = dq->n_element; - } - dq->avg_size_stat = (dq->avg_size_stat*dq->n_stat_samples + dq->n_element)/(++dq->n_stat_samples); -} -void dq_print_stat(delay_queue* dq) { - printf("Max Length: %d, Average Length: %f\n",dq->max_size_stat,dq->avg_size_stat ); -} - - -#ifdef TEST_DQ - -void regresstion_test01() { - delay_queue *dqa, *dqb; - int i; - int a[7]; - for (i=0;i<7;i++) a[i]=i; - - dqa = dq_create("dqa", 0, 7, 0); - for (i=0;i<3;i++) dq_push(dqa, &a[i]); - - for (i=0;i<6;i++) { - dq_print(dqa); - assert(dq_pop(dqa) == 0); - } - dq_print(dqa); - assert(dq_pop(dqa) == &a[0]); - - // shortening queue - dq_print(dqa); - dq_set_min_length(dqa, 4); - // see if data in the queue still persist - dq_print(dqa); - assert(dq_pop(dqa) == &a[1]); - // see if the queue behave with min length = 4 - dq_push(dqa, &a[3]); - dq_print(dqa); - assert(dq_pop(dqa) == &a[2]); - for (i=0;i<2;i++) { - dq_print(dqa); - assert(dq_pop(dqa) == 0); - } - dq_print(dqa); - assert(dq_pop(dqa) == &a[3]); - - // lengthening queue - dq_set_min_length(dqa, 6); - dq_push(dqa, &a[4]); - dq_push(dqa, &a[5]); - for (i=0;i<5;i++) { - dq_print(dqa); - assert(dq_pop(dqa) == 0); - } - dq_print(dqa); - assert(dq_pop(dqa) == &a[4]); - - // queue with no min length - dq_set_min_length(dqa, 0); - dq_print(dqa); - assert(dq_pop(dqa) == &a[5]); - dq_print(dqa); - dq_push(dqa, &a[6]); - dq_print(dqa); - assert(dq_pop(dqa) == &a[6]); - - // lengthening the queue, then shorten it again, - // but with some data exceeding the new min length - // the data should retain. - dq_print(dqa); - dq_set_min_length(dqa, 7); - dq_print(dqa); - dq_push(dqa, &a[0]); - assert(dq_pop(dqa) == 0); - dq_print(dqa); - dq_set_min_length(dqa, 4); - dq_print(dqa); - assert(dq_pop(dqa) == 0); - assert(dq_pop(dqa) == 0); - assert(dq_pop(dqa) == 0); - assert(dq_pop(dqa) == 0); - assert(dq_pop(dqa) == 0); - // This is the 7th pop: min-length is obeyed - assert(dq_pop(dqa) == &a[0]); - dq_print(dqa); - - // Shortening a queue with null entry only - dq_set_min_length(dqa, 0); - assert(dqa->length == 0); - dq_print(dqa); - - // Lengthening - dq_set_min_length(dqa, 6); - assert(dqa->length == 6); - dq_print(dqa); - - // Shortening a queue with null entry only - dq_set_min_length(dqa, 3); - assert(dqa->length == 3); - dq_print(dqa); - - dq_free(dqa); - printf("regression test 01 passed!\n"); -} - -int regresstion_test00() { - delay_queue *dqa, *dqb, *dqc, *dqd; - int i; - int a[4]; - int *b; - for (i=0;i<4;i++) a[i]=i; - dqa = dq_create("dqa", 0, 4, 0); - dqb = dq_create("dqb", 0, 10, 0); - dq_print(dqa); - dq_print(dqb); - dq_push(dqa,a); - dq_print(dqa); - dq_pop(dqa); - dq_print(dqa); - dq_push(dqa,a); - dq_print(dqa); - dq_pop(dqa); - dq_print(dqa); - dq_pop(dqa); - dq_print(dqa); - b = dq_pop(dqa); - dq_print(dqa); - for (i=0;i<4;i++) printf("%d\n",b[i]); - dqc = dq_create("dqc", 0, 0, 3); - for (i=0;i<4;i++) { - if (!dq_push(dqc,&a[i])) printf("cannot push.\n"); - dq_print(dqc); - } - dqd = dq_create("dqd", 0, 2, 3); - if (!dq_push(dqd,&a[0])) printf("cannot push.\n"); - dq_print(dqd); - if (!dq_push(dqd,&a[1])) printf("cannot push.\n"); - dq_print(dqd); - if (!dq_push(dqd,&a[2])) printf("cannot push.\n"); - dq_print(dqd); - dq_pop(dqd); - if (!dq_push(dqd,&a[3])) printf("cannot push.\n"); - dq_print(dqd); - - dq_free(dqa); - dq_free(dqb); - dq_free(dqc); - dq_free(dqd); - - return 0; -} - -int main() { - regresstion_test01(); - return 0; -} - - -#endif diff --git a/src/gpgpu-sim/delayqueue.h b/src/gpgpu-sim/delayqueue.h index a8d6fc1..8392460 100644 --- a/src/gpgpu-sim/delayqueue.h +++ b/src/gpgpu-sim/delayqueue.h @@ -70,51 +70,167 @@ #ifndef DELAYQUEUE_H #define DELAYQUEUE_H -typedef struct delay_data_t delay_data; -struct delay_data_t { - void *data; - unsigned int time_elapsed; - delay_data *next; +#include "../intersim/statwraper.h" +#include "gpu-misc.h" + +template <class T> +struct fifo_data { + T *m_data; + fifo_data *m_next; unsigned long long push_time; //for stat collection }; -typedef struct { - const char* name; - int uid; +template <class T> +class fifo_pipeline { +public: + fifo_pipeline(const char* nm, unsigned int minlen, unsigned int maxlen, unsigned long long current_time ) + { + m_name = nm; + m_min_len = minlen; + m_max_len = maxlen; + m_length = 0; + m_n_element = 0; + m_head = NULL; + m_tail = NULL; + for (unsigned i=0;i<m_min_len;i++) + push(NULL,current_time); + m_lat_stat = StatCreate(m_name,1,32); + } + + ~fifo_pipeline() + { + while (m_head) { + m_tail = m_head; + m_head = m_head->m_next; + delete m_tail; + } + } + + void push(T* data, unsigned long long current_time ) + { + if (m_max_len) assert(m_length < m_max_len); + if (m_head) { + if (m_tail->m_data || m_length < m_min_len) { + m_tail->m_next = new fifo_data<T>(); + m_tail = m_tail->m_next; + m_length++; + m_n_element++; + } + } else { + m_head = m_tail = new fifo_data<T>(); + m_length++; + m_n_element++; + } + m_tail->m_next = NULL; + m_tail->m_data = data; + m_tail->push_time = current_time; + } + + T* pop( unsigned long long current_time ) + { + fifo_data<T>* next; + T* data; + if (m_head) { + next = m_head->m_next; + data = m_head->m_data; + StatAddSample(m_lat_stat, LOGB2 (current_time - m_head->push_time)); + if ( m_head == m_tail ) { + assert( next == NULL ); + m_tail = NULL; + } + delete m_head; + m_head = next; + m_length--; + if (m_length == 0) { + assert( m_head == NULL ); + m_tail = m_head; + } + m_n_element--; + if (m_min_len && m_length < m_min_len) { + push(NULL,current_time); + m_n_element--; // uncount NULL elements inserted to create delays + } + } else { + data = NULL; + } + return data; + } - unsigned int latency; - unsigned int min_len; - unsigned int max_len; - unsigned int length; - unsigned int n_element; + T* top() + { + if (m_head) { + return m_head->m_data; + } else { + return NULL; + } + } - delay_data *head; - delay_data *tail; + void set_min_length(unsigned int new_min_len, unsigned long long current_time) + { + if (new_min_len == m_min_len) return; + + if (new_min_len > m_min_len) { + m_min_len = new_min_len; + while (m_length < m_min_len) { + push(NULL,current_time); + m_n_element--; // uncount NULL elements inserted to create delays + } + } else { + // in this branch imply that the original min_len is larger then 0 + // ie. head != 0 + assert(m_head); + m_min_len = new_min_len; + while ((m_length > m_min_len) && (m_tail->m_data == 0)) { + fifo_data<T> *iter; + iter = m_head; + while (iter && (iter->m_next != m_tail)) + iter = iter->m_next; + if (!iter) { + // there is only one node, and that node is empty + assert(m_head->m_data == 0); + pop(current_time); + } else { + // there are more than one node, and tail node is empty + assert(iter->m_next == m_tail); + delete m_tail; + m_tail = iter; + m_tail->m_next = 0; + m_length--; + } + } + } + } - void* lat_stat; //a pointer to latency stats distribution structure - //occupancy stat - unsigned int max_size_stat; - unsigned int n_stat_samples; - float avg_size_stat; -} delay_queue; + bool full() const { return (m_max_len && m_length >= m_max_len); } + bool empty() const { return m_head == NULL; } + unsigned get_n_element() const { return m_n_element; } + unsigned get_length() const { return m_length; } + unsigned get_max_len() const { return m_max_len; } + void* get_lat_stat() { return m_lat_stat; } -unsigned char dq_full(delay_queue* dq ); -unsigned char dq_empty(delay_queue* dq ); -unsigned int dq_n_element(delay_queue* dq ); -unsigned char dq_push(delay_queue* dq, void* data); -void* dq_pop(delay_queue* dq); -void dq_set_min_length(delay_queue* dq, unsigned int new_min_len); -void removeEntry(void* data, delay_queue** dq, int size_dq); -delay_queue* dq_create( const char* name, - unsigned int latency, - unsigned int min_len, - unsigned int max_len); -void dq_remove(void* data, delay_queue* dq); -void dq_print(delay_queue* dq); -void dq_free(delay_queue* dq); -void* dq_top(delay_queue* dq);//return the data in the head without poping the queue + void print() const + { + fifo_data<T>* ddp = m_head; + printf("%s(%d): ", m_name, m_length); + while (ddp) { + printf("%p ", ddp->m_data); + ddp = ddp->m_next; + } + printf("\n"); + } -void dq_update_stat(delay_queue* dq); -void dq_print_stat(delay_queue* dq); +private: + const char* m_name; + + unsigned int m_min_len; + unsigned int m_max_len; + unsigned int m_length; + unsigned int m_n_element; + + fifo_data<T> *m_head; + fifo_data<T> *m_tail; + + void* m_lat_stat; //a pointer to latency stats distribution structure +}; #endif diff --git a/src/gpgpu-sim/dram.cc b/src/gpgpu-sim/dram.cc index 9f76b96..3182b38 100644 --- a/src/gpgpu-sim/dram.cc +++ b/src/gpgpu-sim/dram.cc @@ -68,195 +68,163 @@ #include "gpu-misc.h" #include "dram.h" #include "mem_latency_stat.h" +#include "dram_sched.h" #ifdef DRAM_VERIFY int PRINT_CYCLE = 0; #endif -dram_t* dram_create( unsigned int id, unsigned int nbk, - unsigned int tCCD, unsigned int tRRD, - unsigned int tRCD, unsigned int tRAS, - unsigned int tRP, unsigned int tRC, - unsigned int CL, unsigned int WL, - unsigned int BL, unsigned int tWTR, - unsigned int busW, unsigned int queue_limit, - unsigned char scheduler_type ) +template class fifo_pipeline<mem_fetch>; +template class fifo_pipeline<dram_req_t>; + +dram_t::dram_t( unsigned int partition_id, struct memory_config *config ) { - dram_t *dm; - unsigned i; + id = partition_id; + m_stats = NULL; + m_config = config; - dm = (dram_t*)calloc(1,sizeof(dram_t)); - dm = new (dm) dram_t(); + BL=m_config->gpgpu_dram_burst_length; + busW=m_config->gpgpu_dram_buswidth; - dm->id = id; + sscanf(m_config->gpgpu_dram_timing_opt,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",&nbk,&tCCD,&tRRD,&tRCD,&tRAS,&tRP,&tRC,&CL,&WL,&tWTR); + m_config->gpu_mem_n_bk = nbk; - dm->nbk = nbk; - dm->tCCD = tCCD; - dm->tRRD = tRRD; - dm->tRCD = tRCD; - dm->tRCDWR = tRCD - (WL + 1); //formula given in datasheet - dm->tRAS = tRAS; - dm->tRP = tRP; - dm->tRC = tRC; - dm->CL = CL; - dm->WL = WL; - dm->BL = BL; + tRCDWR = tRCD - (WL + 1); //formula given in datasheet + tRTW = (CL+(BL/2)+2-WL); //read to write time according to datasheet - dm->tRTW = (CL+(BL/2)+2-WL); //read to write time according to datasheet - dm->tWTR = tWTR; + CCDc = 0; + RRDc = 0; + RTWc = 0; + WTRc = 0; - dm->busW = busW; + rw = READ; //read mode is default - dm->CCDc = 0; - dm->RRDc = 0; - dm->RTWc = 0; - dm->WTRc = 0; + bk = (bank_t**) calloc(sizeof(bank_t*),nbk); + bk[0] = (bank_t*) calloc(sizeof(bank_t),nbk); + for (unsigned i=1;i<nbk;i++) + bk[i] = bk[0] + i; + for (unsigned i=0;i<nbk;i++) + bk[i]->state = BANK_IDLE; - dm->rw = READ; //read mode is default + prio = 0; + rwq = new fifo_pipeline<dram_req_t>("rwq",CL,CL+1,gpu_sim_cycle); + mrqq = new fifo_pipeline<dram_req_t>("mrqq",0,0,gpu_sim_cycle); + returnq = new fifo_pipeline<mem_fetch>("dramreturnq",0,m_config->gpgpu_dram_sched_queue_size,gpu_sim_cycle); + m_fast_ideal_scheduler = NULL; + if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) + m_fast_ideal_scheduler = new ideal_dram_scheduler(this); + n_cmd = 0; + n_activity = 0; + n_nop = 0; + n_act = 0; + n_pre = 0; + n_rd = 0; + n_wr = 0; + n_req = 0; + max_mrqs_temp = 0; + bwutil = 0; + max_mrqs = 0; - dm->bk = (bank_t**) calloc(sizeof(bank_t*),dm->nbk); - dm->bk[0] = (bank_t*) calloc(sizeof(bank_t),dm->nbk); - for (i=1;i<dm->nbk;i++) { - dm->bk[i] = dm->bk[0] + i; + for (unsigned i=0;i<10;i++) { + dram_util_bins[i]=0; + dram_eff_bins[i]=0; } - for (i=0;i<dm->nbk;i++) { - dm->bk[i]->state = BANK_IDLE; - } - dm->prio = 0; - dm->rwq = dq_create("rwq",0,dm->CL,dm->CL+1); - dm->mrqq = dq_create("mrqq",0,0,0); - dm->queue_limit = queue_limit; - - dm->returnq = dq_create("dramreturnq",0,0, queue_limit); - - dm->m_fast_ideal_scheduler = NULL; - if ( scheduler_type == DRAM_IDEAL_FAST ) - dm->m_fast_ideal_scheduler = alloc_fast_ideal_scheduler(dm); - - - dm->n_cmd = 0; - dm->n_activity = 0; - dm->n_nop = 0; - dm->n_act = 0; - dm->n_pre = 0; - dm->n_rd = 0; - dm->n_wr = 0; - dm->n_req = 0; - dm->max_mrqs_temp = 0; + last_n_cmd = last_n_activity = last_bwutil = 0; - dm->bwutil = 0; + n_cmd_partial = 0; + n_activity_partial = 0; + n_nop_partial = 0; + n_act_partial = 0; + n_pre_partial = 0; + n_req_partial = 0; + ave_mrqs_partial = 0; + bwutil_partial = 0; - dm->max_mrqs = 0; - - dm->scheduler_type = scheduler_type; - - dm->realistic_scheduler_mode = READ; //realistic scheduler defaults to read - for (i=0;i<10;i++) { - dm->dram_util_bins[i]=0; - dm->dram_eff_bins[i]=0; - } - dm->last_n_cmd = dm->last_n_activity = dm->last_bwutil = 0; - - dm->n_cmd_partial = 0; - dm->n_activity_partial = 0; - dm->n_nop_partial = 0; - dm->n_act_partial = 0; - dm->n_pre_partial = 0; - dm->n_req_partial = 0; - dm->ave_mrqs_partial = 0; - dm->bwutil_partial = 0; - return dm; + if ( queue_limit() ) + mrqq_Dist = StatCreate("mrqq_length",1, queue_limit()); + else //queue length is unlimited; + mrqq_Dist = StatCreate("mrqq_length",1,64); //track up to 64 entries } -void dram_free( dram_t *dm ) -{ - dq_free(dm->mrqq); - dq_free(dm->rwq); - dq_free( dm->returnq ); - - free(dm->bk[0]); - free(dm->bk); - free(dm); -} - -int dram_full( dram_t *dm ) +int dram_t::full() { int full = 0; - if ( dm->queue_limit == 0 ) return 0; - if ( dm->scheduler_type == DRAM_IDEAL_FAST ) { - unsigned nreqs = fast_scheduler_queue_length(dm) + dq_n_element(dm->mrqq); - full = (nreqs >= dm->queue_limit); + if ( m_config->gpgpu_dram_sched_queue_size == 0 ) return 0; + if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) { + unsigned nreqs = m_fast_ideal_scheduler->num_pending() + mrqq->get_n_element(); + full = (nreqs >= m_config->gpgpu_dram_sched_queue_size); } else { - full = (dm->mrqq->length >= dm->queue_limit); + full = (mrqq->get_length() >= m_config->gpgpu_dram_sched_queue_size); } return full; } -unsigned int dram_que_length( dram_t *dm ) +unsigned int dram_t::que_length() const { unsigned nreqs = 0; - if (dm->scheduler_type == DRAM_IDEAL_FAST ) { - nreqs = fast_scheduler_queue_length(dm); + if (m_config->scheduler_type == DRAM_IDEAL_FAST ) { + nreqs = m_fast_ideal_scheduler->num_pending(); } else { - nreqs = dm->mrqq->length ; + nreqs = mrqq->get_length(); } return nreqs; } -void dram_push( dram_t *dm, unsigned int bank, - unsigned int row, unsigned int col, - unsigned int nbytes, unsigned int write, - unsigned int wid, - unsigned int sid, int cache_hits_waiting, unsigned long long addr, - void *data ) +bool dram_t::returnq_full() const { - dram_req_t *mrq; - - if (bank>=dm->nbk) printf("ERROR: no such bank exist in DRAM %d\n", bank); + return returnq->full(); +} - mrq = (dram_req_t *) malloc(sizeof(dram_req_t)); +unsigned int dram_t::queue_limit() const +{ + return m_config->gpgpu_dram_sched_queue_size; +} - mrq->bk = bank; - mrq->row = row; - mrq->col = col; - mrq->nbytes = nbytes; - mrq->txbytes = 0; - mrq->dqbytes = 0; - mrq->data = data; - mrq->timestamp = gpu_tot_sim_cycle + gpu_sim_cycle; - mrq->cache_hits_waiting = cache_hits_waiting; - mrq->addr = addr; - mrq->insertion_time = (unsigned) gpu_sim_cycle; - if (!write) { - mrq->rw = READ; //request is a read - } else { - mrq->rw = WRITE; //request is a write - } +dram_req_t::dram_req_t( class mem_fetch *mf ) +{ + bk = mf->tlx.bk; + row = mf->tlx.row; + col = mf->tlx.col; + nbytes = mf->nbytes_L1; + txbytes = 0; + dqbytes = 0; + data = mf; + timestamp = gpu_tot_sim_cycle + gpu_sim_cycle; + cache_hits_waiting = mf->cache_hits_waiting; + addr = mf->addr; + insertion_time = (unsigned) gpu_sim_cycle; + rw = data->m_write?WRITE:READ; +} - dq_push(dm->mrqq,mrq); - dm->n_req += 1; - dm->n_req_partial += 1; +void dram_t::push( class mem_fetch *data ) +{ + assert(data->tlx.bk<nbk); + dram_req_t *mrq = new dram_req_t(data); + mrqq->push(mrq,gpu_sim_cycle); - if ( dm->scheduler_type == DRAM_IDEAL_FAST ) { - unsigned nreqs = fast_scheduler_queue_length(dm); - if ( nreqs > dm->max_mrqs_temp) - dm->max_mrqs_temp = nreqs; + // stats... + n_req += 1; + n_req_partial += 1; + if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) { + unsigned nreqs = m_fast_ideal_scheduler->num_pending(); + if ( nreqs > max_mrqs_temp) + max_mrqs_temp = nreqs; } else { - dm->max_mrqs_temp = (dm->max_mrqs_temp > dm->mrqq->length)? dm->max_mrqs_temp : dm->mrqq->length; + max_mrqs_temp = (max_mrqs_temp > mrqq->get_length())? max_mrqs_temp : mrqq->get_length(); } + m_stats->memlatstat_dram_access(data); } -void scheduler_fifo(dram_t* dm) +void dram_t::scheduler_fifo() { - if (dm->mrqq->head) { - dram_req_t *head_mrqq; + if (!mrqq->empty()) { unsigned int bkn; - head_mrqq = (dram_req_t *)dm->mrqq->head->data; + dram_req_t *head_mrqq = mrqq->top(); bkn = head_mrqq->bk; - if (!dm->bk[bkn]->mrq) { - dm->bk[bkn]->mrq = (dram_req_t*) dq_pop(dm->mrqq); + if (!bk[bkn]->mrq) { + bk[bkn]->mrq = mrqq->pop(gpu_sim_cycle); } } } @@ -265,7 +233,7 @@ void scheduler_fifo(dram_t* dm) #define DEC2ZERO(x) x = (x)? (x-1) : 0; #define SWAP(a,b) a ^= b; b ^= a; a ^= b; -void dram_issueCMD (dram_t* dm) +void dram_t::issueCMD() { unsigned i,j,k; unsigned char issued; @@ -274,206 +242,196 @@ void dram_issueCMD (dram_t* dm) /* check if the upcoming request is on an idle bank */ /* Should we modify this so that multiple requests are checked? */ - switch (dm->scheduler_type) { - case DRAM_FIFO: - scheduler_fifo(dm); - break; - case DRAM_IDEAL_FAST: - fast_scheduler_ideal(dm); - break; + switch (m_config->scheduler_type) { + case DRAM_FIFO: scheduler_fifo(); break; + case DRAM_IDEAL_FAST: fast_scheduler_ideal(); break; default: printf("Error: Unknown DRAM scheduler type\n"); assert(0); } - if ( dm->scheduler_type == DRAM_IDEAL_FAST ) { - unsigned nreqs = fast_scheduler_queue_length(dm); - if ( nreqs > dm->max_mrqs) { - dm->max_mrqs = nreqs; + if ( m_config->scheduler_type == DRAM_IDEAL_FAST ) { + unsigned nreqs = m_fast_ideal_scheduler->num_pending(); + if ( nreqs > max_mrqs) { + max_mrqs = nreqs; } - dm->ave_mrqs += nreqs; - dm->ave_mrqs_partial += nreqs; + ave_mrqs += nreqs; + ave_mrqs_partial += nreqs; } else { - if (dm->mrqq->length > dm->max_mrqs) { - dm->max_mrqs = dm->mrqq->length; + if (mrqq->get_length() > max_mrqs) { + max_mrqs = mrqq->get_length(); } - dm->ave_mrqs += dm->mrqq->length; - dm->ave_mrqs_partial += dm->mrqq->length; + ave_mrqs += mrqq->get_length(); + ave_mrqs_partial += mrqq->get_length(); } - k=dm->nbk; + k=nbk; // check if any bank is ready to issue a new read - for (i=0;i<dm->nbk;i++) { - j = (i + dm->prio) % dm->nbk; - if (dm->bk[j]->mrq) { //if currently servicing a memory request + for (i=0;i<nbk;i++) { + j = (i + prio) % nbk; + if (bk[j]->mrq) { //if currently servicing a memory request // correct row activated for a READ - if ( !issued && !dm->CCDc && !dm->bk[j]->RCDc && - (dm->bk[j]->curr_row == dm->bk[j]->mrq->row) && - (dm->bk[j]->mrq->rw == READ) && (dm->WTRc == 0 ) && - (dm->bk[j]->state == BANK_ACTIVE) && - !dq_full(dm->rwq) ) { - if (dm->rw==WRITE) { - dm->rw=READ; - dq_set_min_length(dm->rwq, dm->CL); + if ( !issued && !CCDc && !bk[j]->RCDc && + (bk[j]->curr_row == bk[j]->mrq->row) && + (bk[j]->mrq->rw == READ) && (WTRc == 0 ) && + (bk[j]->state == BANK_ACTIVE) && + !rwq->full() ) { + if (rw==WRITE) { + rw=READ; + rwq->set_min_length(CL,gpu_sim_cycle); } - dq_push(dm->rwq,(void*)dm->bk[j]->mrq); //only push when rwq empty? - dm->bk[j]->mrq->txbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; //16 bytes - dm->CCDc = dm->tCCD; - dm->RTWc = dm->tRTW; + rwq->push(bk[j]->mrq,gpu_sim_cycle); + bk[j]->mrq->txbytes += BL * busW * gpu_n_mem_per_ctrlr; //16 bytes + CCDc = tCCD; + RTWc = tRTW; issued = 1; - dm->n_rd++; - //printf("\tn_rd++ Bank: %d Row: %d Col: %d\n", j, dm->bk[j]->mrq->row, dm->bk[j]->mrq->col); - dm->bwutil+= dm->BL/2; - dm->bwutil_partial += dm->BL/2; - dm->bk[j]->n_access++; + n_rd++; + bwutil+= BL/2; + bwutil_partial += BL/2; + bk[j]->n_access++; #ifdef DRAM_VERIFY PRINT_CYCLE=1; printf("\tRD Bk:%d Row:%03x Col:%03x \n", - j, dm->bk[j]->curr_row, - dm->bk[j]->mrq->col+dm->bk[j]->mrq->txbytes-dm->BL*dm->busW); + j, bk[j]->curr_row, + bk[j]->mrq->col+bk[j]->mrq->txbytes-BL*busW); #endif // transfer done - if ( !(dm->bk[j]->mrq->txbytes < dm->bk[j]->mrq->nbytes) ) { - dm->bk[j]->mrq = NULL; + if ( !(bk[j]->mrq->txbytes < bk[j]->mrq->nbytes) ) { + bk[j]->mrq = NULL; } } else // correct row activated for a WRITE - if ( !issued && !dm->CCDc && !dm->bk[j]->RCDWRc && - (dm->bk[j]->curr_row == dm->bk[j]->mrq->row) && - (dm->bk[j]->mrq->rw == WRITE) && (dm->RTWc == 0 ) && - (dm->bk[j]->state == BANK_ACTIVE) && - !dq_full(dm->rwq) ) { - if (dm->rw==READ) { - dm->rw=WRITE; - dq_set_min_length(dm->rwq, dm->WL); + if ( !issued && !CCDc && !bk[j]->RCDWRc && + (bk[j]->curr_row == bk[j]->mrq->row) && + (bk[j]->mrq->rw == WRITE) && (RTWc == 0 ) && + (bk[j]->state == BANK_ACTIVE) && + !rwq->full() ) { + if (rw==READ) { + rw=WRITE; + rwq->set_min_length(WL,gpu_sim_cycle); } - dq_push(dm->rwq,(void*)dm->bk[j]->mrq); + rwq->push(bk[j]->mrq,gpu_sim_cycle); - dm->bk[j]->mrq->txbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; /*16 bytes*/ - dm->CCDc = dm->tCCD; + bk[j]->mrq->txbytes += BL * busW * gpu_n_mem_per_ctrlr; /*16 bytes*/ + CCDc = tCCD; issued = 1; - dm->n_wr++; - dm->bwutil+=2; - dm->bwutil_partial += dm->BL/2; + n_wr++; + bwutil+=2; + bwutil_partial += BL/2; #ifdef DRAM_VERIFY PRINT_CYCLE=1; printf("\tWR Bk:%d Row:%03x Col:%03x \n", - j, dm->bk[j]->curr_row, - dm->bk[j]->mrq->col+dm->bk[j]->mrq->txbytes-dm->BL*dm->busW); + j, bk[j]->curr_row, + bk[j]->mrq->col+bk[j]->mrq->txbytes-BL*busW); #endif // transfer done - if ( !(dm->bk[j]->mrq->txbytes < dm->bk[j]->mrq->nbytes) ) { - dm->bk[j]->mrq = NULL; + if ( !(bk[j]->mrq->txbytes < bk[j]->mrq->nbytes) ) { + bk[j]->mrq = NULL; } } else // bank is idle - if ( !issued && !dm->RRDc && - (dm->bk[j]->state == BANK_IDLE) && - !dm->bk[j]->RPc && !dm->bk[j]->RCc ) { + if ( !issued && !RRDc && + (bk[j]->state == BANK_IDLE) && + !bk[j]->RPc && !bk[j]->RCc ) { #ifdef DRAM_VERIFY PRINT_CYCLE=1; printf("\tACT BK:%d NewRow:%03x From:%03x \n", - j,dm->bk[j]->mrq->row,dm->bk[j]->curr_row); + j,bk[j]->mrq->row,bk[j]->curr_row); #endif // activate the row with current memory request - dm->bk[j]->curr_row = dm->bk[j]->mrq->row; - dm->bk[j]->state = BANK_ACTIVE; - dm->RRDc = dm->tRRD; - dm->bk[j]->RCDc = dm->tRCD; - dm->bk[j]->RCDWRc = dm->tRCDWR; - dm->bk[j]->RASc = dm->tRAS; - dm->bk[j]->RCc = dm->tRC; - dm->prio = (j + 1) % dm->nbk; + bk[j]->curr_row = bk[j]->mrq->row; + bk[j]->state = BANK_ACTIVE; + RRDc = tRRD; + bk[j]->RCDc = tRCD; + bk[j]->RCDWRc = tRCDWR; + bk[j]->RASc = tRAS; + bk[j]->RCc = tRC; + prio = (j + 1) % nbk; issued = 1; - dm->n_act_partial++; - dm->n_act++; + n_act_partial++; + n_act++; } else // different row activated if ( (!issued) && - (dm->bk[j]->curr_row != dm->bk[j]->mrq->row) && - (dm->bk[j]->state == BANK_ACTIVE) && - (!dm->bk[j]->RASc) ) { - //printf("\tRASc: %d \n", dm->bk[j]->RASc); + (bk[j]->curr_row != bk[j]->mrq->row) && + (bk[j]->state == BANK_ACTIVE) && + (!bk[j]->RASc) ) { // make the bank idle again - dm->bk[j]->state = BANK_IDLE; - dm->bk[j]->RPc = dm->tRP; - dm->prio = (j + 1) % dm->nbk; + bk[j]->state = BANK_IDLE; + bk[j]->RPc = tRP; + prio = (j + 1) % nbk; issued = 1; - dm->n_pre++; - dm->n_pre_partial++; + n_pre++; + n_pre_partial++; #ifdef DRAM_VERIFY PRINT_CYCLE=1; - printf("\tPRE BK:%d Row:%03x \n", j,dm->bk[j]->curr_row); - //printf("\tRASc: %d \n", dm->bk[j]->RASc); + printf("\tPRE BK:%d Row:%03x \n", j,bk[j]->curr_row); #endif } } else { - if (!dm->CCDc && !dm->RRDc && !dm->RTWc && !dm->WTRc && !dm->bk[j]->RCDc && !dm->bk[j]->RASc - && !dm->bk[j]->RCc && !dm->bk[j]->RPc && !dm->bk[j]->RCDWRc) k--; - dm->bk[i]->n_idle++; + if (!CCDc && !RRDc && !RTWc && !WTRc && !bk[j]->RCDc && !bk[j]->RASc + && !bk[j]->RCc && !bk[j]->RPc && !bk[j]->RCDWRc) k--; + bk[i]->n_idle++; } } if (!issued) { - dm->n_nop++; - dm->n_nop_partial++; + n_nop++; + n_nop_partial++; #ifdef DRAM_VIEWCMD printf("\tNOP "); #endif } if (k) { - dm->n_activity++; - dm->n_activity_partial++; + n_activity++; + n_activity_partial++; } - dm->n_cmd++; - dm->n_cmd_partial++; + n_cmd++; + n_cmd_partial++; // decrements counters once for each time dram_issueCMD is called - DEC2ZERO(dm->RRDc); - DEC2ZERO(dm->CCDc); - DEC2ZERO(dm->RTWc); - DEC2ZERO(dm->WTRc); - for (j=0;j<dm->nbk;j++) { - DEC2ZERO(dm->bk[j]->RCDc); - DEC2ZERO(dm->bk[j]->RASc); - DEC2ZERO(dm->bk[j]->RCc); - DEC2ZERO(dm->bk[j]->RPc); - DEC2ZERO(dm->bk[j]->RCDWRc); + DEC2ZERO(RRDc); + DEC2ZERO(CCDc); + DEC2ZERO(RTWc); + DEC2ZERO(WTRc); + for (j=0;j<nbk;j++) { + DEC2ZERO(bk[j]->RCDc); + DEC2ZERO(bk[j]->RASc); + DEC2ZERO(bk[j]->RCc); + DEC2ZERO(bk[j]->RPc); + DEC2ZERO(bk[j]->RCDWRc); } #ifdef DRAM_VISUALIZE - dram_visualize(dm); + visualize(); #endif } //if mrq is being serviced by dram, gets popped after CL latency fulfilled -void* dram_pop( dram_t *dm ) -{ +class mem_fetch* dram_t::pop() +{ dram_req_t *mrq; - void *data; + class mem_fetch *data; unsigned dq_latency; data = NULL; - mrq = (dram_req_t*)dq_pop(dm->rwq); + mrq = rwq->pop(gpu_sim_cycle); if (mrq) { - // data = mrq->data; #ifdef DRAM_VIEWCMD printf("\tDQ: BK%d Row:%03x Col:%03x", mrq->bk, mrq->row, mrq->col + mrq->dqbytes); #endif - mrq->dqbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; /*16 bytes*/ + mrq->dqbytes += BL * busW * gpu_n_mem_per_ctrlr; /*16 bytes*/ if (mrq->dqbytes >= mrq->nbytes) { - - if (gpgpu_memlatency_stat) { + if (m_config->gpgpu_memlatency_stat) { dq_latency = gpu_sim_cycle + gpu_tot_sim_cycle - mrq->timestamp; - dq_lat_table[LOGB2(dq_latency)]++; - if (dq_latency > max_dq_latency) - max_dq_latency = dq_latency; + m_stats->dq_lat_table[LOGB2(dq_latency)]++; + if (dq_latency > m_stats->max_dq_latency) + m_stats->max_dq_latency = dq_latency; } data = mrq->data; - - free(mrq); + delete mrq; } } #ifdef DRAM_VIEWCMD @@ -483,17 +441,33 @@ void* dram_pop( dram_t *dm ) return data; } +void dram_t::returnq_push( class mem_fetch *mf, unsigned long long gpu_sim_cycle) +{ + returnq->push(mf,gpu_sim_cycle); +} + +class mem_fetch* dram_t::returnq_pop( unsigned long long gpu_sim_cycle) +{ + return returnq->pop(gpu_sim_cycle); +} + +class mem_fetch* dram_t::returnq_top() +{ + return returnq->top(); +} + + // a hack to allow peeking into what memory request will be serviced. -void* dram_top( dram_t *dm ) +class mem_fetch* dram_t::top() { dram_req_t *mrq; - void *data; + class mem_fetch *data; data = NULL; - mrq = (dram_req_t*)dq_top(dm->rwq); + mrq = rwq->top(); if (mrq) { // number of bytes returned from dram if this is ever popped - unsigned tobe_dqbytes = mrq->dqbytes + dm->BL * dm->busW * gpu_n_mem_per_ctrlr; + unsigned tobe_dqbytes = mrq->dqbytes + BL * busW * gpu_n_mem_per_ctrlr; if (tobe_dqbytes >= mrq->nbytes) { data = mrq->data; } @@ -502,82 +476,112 @@ void* dram_top( dram_t *dm ) return data; } -void dram_print( dram_t* dm, FILE* simFile) +void dram_t::print( FILE* simFile) const { unsigned i; fprintf(simFile,"DRAM[%d]: %d bks, busW=%d BL=%d CL=%d, ", - dm->id, dm->nbk, dm->busW, dm->BL, dm->CL ); + id, nbk, busW, BL, CL ); fprintf(simFile,"tRRD=%d tCCD=%d, tRCD=%d tRAS=%d tRP=%d tRC=%d\n", - dm->tCCD, dm->tRRD, dm->tRCD, dm->tRAS, dm->tRP, dm->tRC ); + tCCD, tRRD, tRCD, tRAS, tRP, tRC ); fprintf(simFile,"n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_req=%d n_rd=%d n_write=%d bw_util=%.4g\n", - dm->n_cmd, dm->n_nop, dm->n_act, dm->n_pre, dm->n_req, dm->n_rd, dm->n_wr, - (float)dm->bwutil/dm->n_cmd); + n_cmd, n_nop, n_act, n_pre, n_req, n_rd, n_wr, + (float)bwutil/n_cmd); fprintf(simFile,"n_activity=%d dram_eff=%.4g\n", - dm->n_activity, (float)dm->bwutil/dm->n_activity); - for (i=0;i<dm->nbk;i++) { - fprintf(simFile, "bk%d: %da %di ",i,dm->bk[i]->n_access,dm->bk[i]->n_idle); + n_activity, (float)bwutil/n_activity); + for (i=0;i<nbk;i++) { + fprintf(simFile, "bk%d: %da %di ",i,bk[i]->n_access,bk[i]->n_idle); } fprintf(simFile, "\n"); fprintf(simFile, "dram_util_bins:"); - for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_util_bins[i]); + for (i=0;i<10;i++) fprintf(simFile, " %d", dram_util_bins[i]); fprintf(simFile, "\ndram_eff_bins:"); - for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_eff_bins[i]); + for (i=0;i<10;i++) fprintf(simFile, " %d", dram_eff_bins[i]); fprintf(simFile, "\n"); - /* - { - delay_data* mrq; - mrq = dm->mrqq->head; - while (mrq) { - printf("%d",((dram_req_t*)mrq->data)->bk); - mrq = mrq->next; - } - printf("\n"); - } - */ - fprintf(simFile, "mrqq: max=%d avg=%g\n", dm->max_mrqs, (float)dm->ave_mrqs/dm->n_cmd); + fprintf(simFile, "mrqq: max=%d avg=%g\n", max_mrqs, (float)ave_mrqs/n_cmd); } -void dram_visualize( dram_t* dm ) +void dram_t::visualize() const { - unsigned i; - printf("RRDc=%d CCDc=%d mrqq.Length=%d rwq.Length=%d\n", - dm->RRDc, dm->CCDc, dm->mrqq->length,dm->rwq->length); - for (i=0;i<dm->nbk;i++) { + RRDc, CCDc, mrqq->get_length(),rwq->get_length()); + for (unsigned i=0;i<nbk;i++) { printf("BK%d: state=%c curr_row=%03x, %2d %2d %2d %2d %p ", - i, dm->bk[i]->state, dm->bk[i]->curr_row, - dm->bk[i]->RCDc, dm->bk[i]->RASc, - dm->bk[i]->RPc, dm->bk[i]->RCc, - dm->bk[i]->mrq ); - if (dm->bk[i]->mrq) - printf("txf: %d %d", dm->bk[i]->mrq->nbytes, dm->bk[i]->mrq->txbytes); + i, bk[i]->state, bk[i]->curr_row, + bk[i]->RCDc, bk[i]->RASc, + bk[i]->RPc, bk[i]->RCc, + bk[i]->mrq ); + if (bk[i]->mrq) + printf("txf: %d %d", bk[i]->mrq->nbytes, bk[i]->mrq->txbytes); printf("\n"); } - if ( dm->m_fast_ideal_scheduler ) { - dump_fast_ideal_scheduler( dm ); - } - + if ( m_fast_ideal_scheduler ) + m_fast_ideal_scheduler->print(stdout); } -void dram_print_stat( dram_t* dm, FILE* simFile ) +void dram_t::print_stat( FILE* simFile ) { - int i; fprintf(simFile,"DRAM (%d): n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_req=%d n_rd=%d n_write=%d bw_util=%.4g ", - dm->id, dm->n_cmd, dm->n_nop, dm->n_act, dm->n_pre, dm->n_req, dm->n_rd, dm->n_wr, - (float)dm->bwutil/dm->n_cmd); - fprintf(simFile, "mrqq: %d %.4g mrqsmax=%d ", dm->max_mrqs, (float)dm->ave_mrqs/dm->n_cmd, dm->max_mrqs_temp); + id, n_cmd, n_nop, n_act, n_pre, n_req, n_rd, n_wr, + (float)bwutil/n_cmd); + fprintf(simFile, "mrqq: %d %.4g mrqsmax=%d ", max_mrqs, (float)ave_mrqs/n_cmd, max_mrqs_temp); fprintf(simFile, "\n"); fprintf(simFile, "dram_util_bins:"); - for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_util_bins[i]); + for (unsigned i=0;i<10;i++) fprintf(simFile, " %d", dram_util_bins[i]); fprintf(simFile, "\ndram_eff_bins:"); - for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_eff_bins[i]); + for (unsigned i=0;i<10;i++) fprintf(simFile, " %d", dram_eff_bins[i]); fprintf(simFile, "\n"); - dm->max_mrqs_temp = 0; + max_mrqs_temp = 0; } - -unsigned dram_busy( dram_t* dm) +void dram_t::queue_latency_log_dump( FILE *fp ) { - return !dm->m_request_tracker.empty(); + fprintf(fp,"(LOGB2)Latency DRAM[%d] ",id); + StatDisp(mrqq->get_lat_stat()); + fprintf(fp,"(LOGB2)Latency DRAM[%d] ",id); + StatDisp(rwq->get_lat_stat()); + dram_log(DUMPLOG); } +void dram_t::visualizer_print( gzFile visualizer_file ) +{ + // dram specific statistics + gzprintf(visualizer_file,"dramncmd: %u %u\n",id, n_cmd_partial); + gzprintf(visualizer_file,"dramnop: %u %u\n",id,n_nop_partial); + gzprintf(visualizer_file,"dramnact: %u %u\n",id,n_act_partial); + gzprintf(visualizer_file,"dramnpre: %u %u\n",id,n_pre_partial); + gzprintf(visualizer_file,"dramnreq: %u %u\n",id,n_req_partial); + gzprintf(visualizer_file,"dramavemrqs: %u %u\n",id, + n_cmd_partial?(ave_mrqs_partial/n_cmd_partial ):0); + + // utilization and efficiency + gzprintf(visualizer_file,"dramutil: %u %u\n", + id,n_cmd_partial?100*bwutil_partial/n_cmd_partial:0); + gzprintf(visualizer_file,"drameff: %u %u\n", + id,n_activity_partial?100*bwutil_partial/n_activity_partial:0); + + // reset for next interval + bwutil_partial = 0; + n_activity_partial = 0; + ave_mrqs_partial = 0; + n_cmd_partial = 0; + n_nop_partial = 0; + n_act_partial = 0; + n_pre_partial = 0; + n_req_partial = 0; + + // dram access type classification + for (unsigned j = 0; j < m_config->gpu_mem_n_bk; j++) { + gzprintf(visualizer_file,"dramglobal_acc_r: %u %u %u\n", id, j, + m_stats->mem_access_type_stats[GLOBAL_ACC_R][id][j]); + gzprintf(visualizer_file,"dramglobal_acc_w: %u %u %u\n", id, j, + m_stats->mem_access_type_stats[GLOBAL_ACC_W][id][j]); + gzprintf(visualizer_file,"dramlocal_acc_r: %u %u %u\n", id, j, + m_stats->mem_access_type_stats[LOCAL_ACC_R][id][j]); + gzprintf(visualizer_file,"dramlocal_acc_w: %u %u %u\n", id, j, + m_stats->mem_access_type_stats[LOCAL_ACC_W][id][j]); + gzprintf(visualizer_file,"dramconst_acc_r: %u %u %u\n", id, j, + m_stats->mem_access_type_stats[CONST_ACC_R][id][j]); + gzprintf(visualizer_file,"dramtexture_acc_r: %u %u %u\n", id, j, + m_stats->mem_access_type_stats[TEXTURE_ACC_R][id][j]); + } +} diff --git a/src/gpgpu-sim/dram.h b/src/gpgpu-sim/dram.h index 34be319..68b2474 100644 --- a/src/gpgpu-sim/dram.h +++ b/src/gpgpu-sim/dram.h @@ -1,5 +1,5 @@ /* - * dram.c + * dram.cc * * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, George L. Yuan, * Ivan Sham, Justin Kwong, Dan O'Connor and the @@ -66,28 +66,24 @@ * Vancouver, BC V6T 1Z4 */ -#include <stdio.h> -#include <stdlib.h> +#ifndef DRAM_H +#define DRAM_H #include "delayqueue.h" #include "../cuda-sim/dram_callback.h" #include <set> - -#ifndef DRAM_H -#define DRAM_H - -#define FIFO_AGE_LIMIT 50 //used for both BANK_CONF and REALISTIC schedulers -#define FIFO_NUM_WRITE_LIMIT 3 //used for both BANK_CONF and REALISTIC schedulers -#define LOOKAHEAD_VALUE 10 //used for REALISTIC scheduler ONLY - -enum dram_ctrl_t { - DRAM_FIFO=0, - DRAM_IDEAL_FAST=1 -}; +#include <zlib.h> +#include <stdio.h> +#include <stdlib.h> #define READ 'R' //define read and write states #define WRITE 'W' -typedef struct { +#define BANK_IDLE 'I' +#define BANK_ACTIVE 'A' + +struct dram_req_t +{ + dram_req_t( class mem_fetch *data ); unsigned int row; unsigned int col; unsigned int bk; @@ -99,15 +95,12 @@ typedef struct { unsigned char rw; //is the request a read or a write? unsigned long long int addr; unsigned int insertion_time; - void* data; - + class mem_fetch * data; int cache_hits_waiting; -} dram_req_t; - -#define BANK_IDLE 'I' -#define BANK_ACTIVE 'A' +}; -typedef struct { +struct bank_t +{ unsigned int RCDc; unsigned int RCDWRc; unsigned int RASc; @@ -123,13 +116,45 @@ typedef struct { unsigned int n_access; unsigned int n_writes; unsigned int n_idle; -} bank_t; +}; struct mem_fetch; -typedef struct dram_timing { +class dram_t +{ +public: + dram_t( unsigned int parition_id, struct memory_config *config); + + void set_stats( class memory_stats_t *stats ) {m_stats=stats;} + + int full(); + class mem_fetch* top(); + void print( FILE* simFile ) const; + void visualize() const; + void print_stat( FILE* simFile ); + unsigned int que_length() const; + bool returnq_full() const; + unsigned int queue_limit() const; + void visualizer_print( gzFile visualizer_file ); + + class mem_fetch* pop(); + void returnq_push( class mem_fetch *mf, unsigned long long gpu_sim_cycle); + class mem_fetch* returnq_pop( unsigned long long gpu_sim_cycle); + class mem_fetch* returnq_top(); + void push( class mem_fetch *data ); + void issueCMD(); + void queue_latency_log_dump( FILE *fp ); + void dram_log (int task); + + struct memory_partition_unit *m_memory_partition_unit; unsigned int id; +private: + void scheduler_fifo(); + void fast_scheduler_ideal(); + + struct memory_config *m_config; + unsigned int tCCD; //column to column delay unsigned int tRRD; //minimal time required between activation of rows in different banks unsigned int tRCD; //row to column delay - time required to activate a row before a read @@ -157,21 +182,17 @@ typedef struct dram_timing { unsigned char rw; //was last request a read or write? (important for RTW, WTR) unsigned int pending_writes; - unsigned char realistic_scheduler_mode; - delay_queue *rwq; - delay_queue *mrqq; + fifo_pipeline<dram_req_t> *rwq; + fifo_pipeline<dram_req_t> *mrqq; //buffer to hold packets when DRAM processing is over //should be filled with dram clock and popped with l2or icnt clock - delay_queue *returnq; - + fifo_pipeline<mem_fetch> *returnq; unsigned int dram_util_bins[10]; unsigned int dram_eff_bins[10]; unsigned int last_n_cmd, last_n_activity, last_bwutil; - unsigned int queue_limit; - unsigned int n_cmd; unsigned int n_activity; unsigned int n_nop; @@ -185,11 +206,8 @@ typedef struct dram_timing { unsigned int bwutil; unsigned int max_mrqs; unsigned int ave_mrqs; - unsigned char scheduler_type; - - void *m_fast_ideal_scheduler; - void *m_L2cache; + class ideal_dram_scheduler* m_fast_ideal_scheduler; unsigned int n_cmd_partial; unsigned int n_activity_partial; @@ -200,41 +218,10 @@ typedef struct dram_timing { unsigned int ave_mrqs_partial; unsigned int bwutil_partial; - void * req_hist; + struct memory_stats_t *m_stats; + class Stats* mrqq_Dist; //memory request queue inside DRAM - std::set<mem_fetch*> m_request_tracker; -} dram_t; - - -dram_t* dram_create( unsigned int id, unsigned int nbk, - unsigned int tCCD, unsigned int tRRD, - unsigned int tRCD, unsigned int tRAS, - unsigned int tRP, unsigned int tRC, - unsigned int CL, unsigned int WL, - unsigned int BL, unsigned int tWTR, - unsigned int busW, unsigned int queue_limit, - unsigned char scheduler_type ); -void dram_free( dram_t *dm ); -int dram_full( dram_t *dm ); -void dram_push( dram_t *dm, unsigned int bank, - unsigned int row, unsigned int col, - unsigned int nbytes, unsigned int write, - unsigned int wid, unsigned int sid, int cache_hits_waiting, unsigned long long addr, - void *data ); -void scheduler_fifo(dram_t* dm); -void dram_issueCMD (dram_t* dm); -void* dram_pop( dram_t *dm ); -void* dram_top( dram_t *dm ); -unsigned dram_busy( dram_t *dm); -void dram_print( dram_t* dm, FILE* simFile ); -void dram_visualize( dram_t* dm ); -void dram_print_stat( dram_t* dm, FILE* simFile ); -void fast_scheduler_ideal(dram_t* dm); -void* alloc_fast_ideal_scheduler(dram_t *dm); -void dump_fast_ideal_scheduler(dram_t *dm); -unsigned fast_scheduler_queue_length(dram_t *dm); - -//supposed to return the current queue length for all memory scheduler types. -unsigned int dram_que_length( dram_t *dm ); + friend class ideal_dram_scheduler; +}; #endif /*DRAM_H*/ diff --git a/src/gpgpu-sim/dram_sched.cc b/src/gpgpu-sim/dram_sched.cc index e678042..1e36b05 100644 --- a/src/gpgpu-sim/dram_sched.cc +++ b/src/gpgpu-sim/dram_sched.cc @@ -170,21 +170,13 @@ void ideal_dram_scheduler::print( FILE *fp ) } } -void* alloc_fast_ideal_scheduler(dram_t *dm) +void dram_t::fast_scheduler_ideal() { - return new ideal_dram_scheduler(dm); -} - -void fast_scheduler_ideal(dram_t* dm) -{ - - + dram_t* dm=this; unsigned mrq_latency; - // replacement for scheduler_ideal() - - ideal_dram_scheduler *sched = reinterpret_cast<ideal_dram_scheduler*>( dm->m_fast_ideal_scheduler ); - while ( !dq_empty(dm->mrqq) && (!gpgpu_dram_sched_queue_size || sched->num_pending() < (unsigned) gpgpu_dram_sched_queue_size)) { - dram_req_t *req = (dram_req_t*)dq_pop(dm->mrqq); + ideal_dram_scheduler *sched = dm->m_fast_ideal_scheduler; + while ( !dm->mrqq->empty() && (!m_config->gpgpu_dram_sched_queue_size || sched->num_pending() < m_config->gpgpu_dram_sched_queue_size)) { + dram_req_t *req = dm->mrqq->pop(gpu_sim_cycle); sched->add_req(req); } @@ -199,12 +191,12 @@ void fast_scheduler_ideal(dram_t* dm) if ( req ) { dm->prio = (dm->prio+1)%dm->nbk; dm->bk[b]->mrq = req; - if (gpgpu_memlatency_stat) { + if (m_config->gpgpu_memlatency_stat) { mrq_latency = gpu_sim_cycle + gpu_tot_sim_cycle - dm->bk[b]->mrq->timestamp; dm->bk[b]->mrq->timestamp = gpu_tot_sim_cycle + gpu_sim_cycle; - mrq_lat_table[LOGB2(mrq_latency)]++; - if (mrq_latency > max_mrq_latency) { - max_mrq_latency = mrq_latency; + m_stats->mrq_lat_table[LOGB2(mrq_latency)]++; + if (mrq_latency > m_stats->max_mrq_latency) { + m_stats->max_mrq_latency = mrq_latency; } } @@ -213,24 +205,3 @@ void fast_scheduler_ideal(dram_t* dm) } } } - - - -void dump_fast_ideal_scheduler( dram_t *dm ) -{ - ideal_dram_scheduler *sched = reinterpret_cast<ideal_dram_scheduler*>( dm->m_fast_ideal_scheduler ); - sched->print(stdout); -} - -unsigned fast_scheduler_queue_length(dram_t *dm) -{ - if (dm->m_fast_ideal_scheduler ) { - ideal_dram_scheduler *sched = reinterpret_cast<ideal_dram_scheduler*>( dm->m_fast_ideal_scheduler ); - return sched->num_pending(); - } else { - printf("fast_scheduler_queue_length(): Where did the scheduler go?\n"); - exit(1); - } -} - - diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index 013ca54..bfd8772 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -81,14 +81,21 @@ shd_cache_line_t* shd_cache_access_internal( shd_cache_t *cp, unsigned int sim_cycle, unsigned int real_access); -shd_cache_t * shd_cache_create( char *name, - unsigned int nset, - unsigned int assoc, - unsigned int line_sz, - unsigned char policy, +shd_cache_t * shd_cache_create( const char *name, + const char *opt, unsigned int hit_latency, unsigned long long int bank_mask, - enum cache_write_policy wp) { + enum cache_write_policy wp) +{ + unsigned int nset; + unsigned int line_sz; + unsigned int assoc; + unsigned char policy; + int ntok = sscanf(opt,"%d:%d:%d:%c", &nset, &line_sz, &assoc, &policy); + if( ntok != 4 ) { + printf("GPGPU-Sim uArch: cache configuration string parsing error for cache %s\n", name); + abort(); + } shd_cache_t *cp; unsigned int nlines; @@ -130,10 +137,6 @@ shd_cache_t * shd_cache_create( char *name, cp->prev_snapshot_miss = 0; cp->prev_snapshot_merge_hit = 0; -// printf("%s: %d(%x) x %d x %d(%x) %c, %d\n", -// cp->name, cp->nset, cp->nset_log2, cp->assoc, cp->line_sz, -// cp->line_sz_log2, cp->policy, nlines); - return cp; } @@ -203,142 +206,115 @@ shd_cache_line_t* shd_cache_access( shd_cache_t *cp, unsigned char write, unsigned int sim_cycle ) { + assert( cp->write_policy != write_back ); return shd_cache_access_internal(cp,addr,nbytes,write,sim_cycle,1/*this is a real access*/); } -shd_cache_t *test = NULL; -enum cache_request_status shd_cache_access_wb( shd_cache_t *cp, +enum cache_request_status shd_cache_access_new( shd_cache_t *cp, unsigned long long int addr, unsigned int nbytes, unsigned char write, unsigned int sim_cycle, address_type *wb_address) { - unsigned int i; - unsigned int set; - unsigned long long int tag; - unsigned long long int packed_addr; - shd_cache_line_t *pline; - - unsigned already_reserved = 0; - unsigned all_reserved = 1; - shd_cache_line_t *free_line = NULL; + unsigned long long int bank_addr; // offset within bank + bool all_reserved = true; + shd_cache_line_t *pending_line = NULL; + shd_cache_line_t *clean_line = NULL; if (cp->bank_mask) - packed_addr = addrdec_packbits(cp->bank_mask, addr, 64, 0); + bank_addr = addrdec_packbits(cp->bank_mask, addr, 64, 0); else - packed_addr = addr; + bank_addr = addr; - set = (packed_addr >> cp->line_sz_log2) & ( (1<<cp->nset_log2) - 1 ); - tag = packed_addr >> (cp->line_sz_log2 + cp->nset_log2); + unsigned set = (bank_addr >> cp->line_sz_log2) & ( (1<<cp->nset_log2) - 1 ); + unsigned long long tag = bank_addr >> (cp->line_sz_log2 + cp->nset_log2); cp->access++; shader_cache_access_log(cp->core_id, cp->type_id, 0); - for (i=0; i<cp->assoc; i++) { - pline = &(cp->lines[set*cp->assoc+i] ); - if (pline->tag == tag) { - if (pline->status & RESERVED) { - already_reserved = 1; + for (unsigned way=0; way<cp->assoc; way++) { + shd_cache_line_t *line = &(cp->lines[set*cp->assoc+way] ); + if (line->tag == tag) { + if (line->status & RESERVED) { + pending_line = line; break; - } else if (pline->status & VALID) { - //printf("Cache Hit! Addr=%08x Set=%x Way=%x Tag=%x\n", packed_addr, set, i, tag); - pline->last_used = sim_cycle; - if (write) { - pline->status |= DIRTY; - } - //return pline; - if (cp->write_policy == write_through) return HIT_W_WT; + } else if (line->status & VALID) { + line->last_used = sim_cycle; + if (write) + line->status |= DIRTY; + if (cp->write_policy == write_through) + return HIT_W_WT; return HIT; } } - if (!(pline->status & RESERVED)) { - all_reserved = 0; - if (!(pline->status & VALID)) { - free_line = pline; - } + if (!(line->status & RESERVED)) { + all_reserved = false; + if (!(line->status & VALID)) + clean_line = line; } } cp->miss++; shader_cache_access_log(cp->core_id, cp->type_id, 1); - if (already_reserved || cp->write_policy != write_back || write) { - //not in cache yet, but no wb as place is reserved. - //or wt caches never nead to worry about it (as do no_write caches) - //or is a write - if (already_reserved && write) { - //write the data into the cache line, make it dirty - //up to mshrs to save write mask to not overwrite this data when the read returns - pline->status |= DIRTY; - return WB_HIT_ON_MISS; - } else if (already_reserved) { + if (pending_line || cp->write_policy != write_back || write) { + if (pending_line) { + if( write ) // write hit-under-miss (irrelevant whether write-back or write-through) + // - timing assumes a large enough write buffer in shader core that we never + // encounter a structural hazard + // - write buffer merged with returning cache block in zero cycles + pending_line->status |= DIRTY; return WB_HIT_ON_MISS; } return MISS_NO_WB; } - //if not in cache, and a write back cache, and not already allocated, need to allocate a place for this request + // at this point: this must be a write back cache (and not a hit-under-miss) + assert( cp->write_policy == write_back ); - if (all_reserved) { - //cannot service this request, because we can't garantee that we have room for the line when it comes back + if (all_reserved) + // cannot service this request, because we can't garantee that we have room for the line when it comes back return RESERVATION_FAIL; - } - - //printf("RESRV %d\n",tag); - if (free_line) { - //reserve fo this request - free_line->status |= RESERVED; - free_line->tag = tag; - //no writeback - return MISS_NO_WB; + if (clean_line) { + // found a clean line in the cache so, no need to do a writeback + clean_line->status |= RESERVED; + clean_line->tag = tag; + return MISS_NO_WB; } - // need to kick a line out to reserve a spot - shd_cache_line_t *rline = NULL; + // no clean lines, need to kick a line out to reserve a spot + shd_cache_line_t *wb_line = NULL; - for (i=0; i<cp->assoc; i++) { - pline = &(cp->lines[set*cp->assoc+i] ); - if (pline->status & VALID && !(pline->status & RESERVED)) { - if (!rline) { - rline = pline; //select first available for ejection for later comparison + for (unsigned way=0; way<cp->assoc; way++) { + shd_cache_line_t *line = &(cp->lines[set*cp->assoc+way] ); + if (line->status & VALID && !(line->status & RESERVED)) { + if (!wb_line) { + wb_line = line; continue; } switch (cp->policy) { case LRU: - if (pline->last_used < rline->last_used) - rline = pline; + if (line->last_used < wb_line->last_used) + wb_line = line; break; case FIFO: - if (pline->fetch_time < rline->fetch_time) - rline = pline; + if (line->fetch_time < wb_line->fetch_time) + wb_line = line; break; default: - rline = pline; //pick one, ie. the last valied one. + abort(); } } } - assert(rline); //ensure we actually found one. - - unsigned needs_wb = (rline->status & (DIRTY|VALID)) == (DIRTY|VALID); - /* Set the replaced cache line address */ - if (needs_wb) { - *wb_address = rline->addr; - } + assert(wb_line); // should always find a line + assert((wb_line->status & (DIRTY|VALID)) == (DIRTY|VALID)); // should be dirty (or we would have found a clean line earlier) - /* reserve this new line */ - rline->status |= RESERVED; - rline->status &= ~VALID; - rline->status &= ~DIRTY; - rline->tag = tag; + // reserve line + wb_line->status = RESERVED; + wb_line->tag = tag; + *wb_address = wb_line->addr; - /* printf("Fetching! Addr=%08x ReplAddr=%08x(%d) Set=%x Tag=%x\n", - packed_addr, repl_addr, nofreeslot, set, tag); - */ - if (needs_wb) { - return MISS_W_WB; - } else { - return MISS_NO_WB; - } + return MISS_W_WB; } shd_cache_line_t* shd_cache_probe( shd_cache_t *cp, @@ -439,9 +415,6 @@ unsigned long long int shd_cache_fill( shd_cache_t *cp, } } - //if (cline) printf("FOUND %d\n",tag); - //else printf("UNFOUND!!! %d\n", tag); - if (!cline) printf("----!!! about to abort - this probably happened because global memory msrh merging is not enabled with a writeback cache !!!----\n"); assert(cline); //error if it doesn't have a reserved space @@ -518,9 +491,6 @@ unsigned long long int shd_cache_fill( shd_cache_t *cp, cline->last_used = sim_cycle; cline->fetch_time = sim_cycle; -/* printf("Fetching! Addr=%08x ReplAddr=%08x(%d) Set=%x Tag=%x\n", - packed_addr, repl_addr, nofreeslot, set, tag); - */ return repl_addr; } @@ -529,7 +499,8 @@ void shd_cache_mergehit( shd_cache_t *cp, unsigned long long int addr ) cp->merge_hit += 1; } -void shd_cache_print( shd_cache_t *cp, FILE *stream) { +void shd_cache_print( const shd_cache_t *cp, FILE *stream, unsigned &total_access, unsigned &total_misses ) +{ fprintf( stream, "Cache %s:\t", cp->name); fprintf( stream, "Size = %d B (%d Set x %d-way x %d byte line)\n", cp->line_sz * cp->nset * cp->assoc, @@ -537,67 +508,6 @@ void shd_cache_print( shd_cache_t *cp, FILE *stream) { fprintf( stream, "\t\tAccess = %d, Miss = %d (%.3g), -MgHts = %d (%.3g)\n", cp->access, cp->miss, (float) cp->miss / cp->access, cp->miss - cp->merge_hit, (float) (cp->miss - cp->merge_hit) / cp->access); + total_misses+=cp->miss; + total_access+=cp->access; } - -#ifdef UNIT_TEST - -int main() { - shd_cache_t *cp[3]; - unsigned int addr, i; - unsigned int cachenum; - unsigned int sim_cycle; - - unsigned int test_addrs[8] = { 0x100, 0x200, 0x300, 0x400, - 0x104, 0x204, 0x500, 0x100}; - unsigned int repl_addr[8] = {0,0,0,0,0,0,0,0}; - unsigned int rdwr[8] = {0,1,0,0,0,0,0,0}; - - sim_cycle = 0; - cp[0] = shd_cache_create ("cp1", 16, 4, 16, LRU, 1); - cp[1] = shd_cache_create ("cp2", 16, 4, 16, FIFO, 1); - - for (cachenum = 0; cachenum<2; cachenum++) - for (i=0; i<8; i++) { - if ( !shd_cache_access(cp[cachenum], test_addrs[i], 4, rdwr[i], sim_cycle) ) { - repl_addr[i] = shd_cache_fill(cp[cachenum], test_addrs[i], sim_cycle); - shd_cache_access(cp[cachenum], test_addrs[i], 4, rdwr[i], sim_cycle); - } - sim_cycle++; - } - - printf("replaced address:"); - for (i=0; i<8; i++) { - printf("0x%x ", repl_addr[i]); - } - printf("\n"); - shd_cache_print(cp[0],stdout); - shd_cache_print(cp[1],stdout); - - shd_cache_fill(cp[0], 0x104b3ecb0, sim_cycle); - printf("Accessing 64-bit address tag: %d\n", - shd_cache_access(cp[0], 0x104b3ecb2, 4, 0, sim_cycle)); - printf("Accessing 64-bit address tag: %d\n", - shd_cache_access(cp[0], 0x103433330, 4, 0, sim_cycle)); - - - shd_set_coherency_policy(2); - cp[2] = shd_cache_create("cp2", 16, 4, 16, LRU, 1); - shd_cache_fill(cp[2], 0x12345000, 0); - shd_cache_access(cp[2], 0x12345000, 4, 1, 0); - shd_cache_access(cp[2], 0x12345004, 4, 0, 0); - shd_cache_access(cp[2], 0x12345008, 4, 0, 0); - shd_cache_access(cp[2], 0x1234500C, 4, 1, 0); - printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0xf, - shd_cache_linedirty(cp[2], 0x12345000, 0xf), 1 ); - printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x6, - shd_cache_linedirty(cp[2], 0x12345000, 0x6), 0 ); - printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x1, - shd_cache_linedirty(cp[2], 0x12345000, 0x1), 1 ); - printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x8, - shd_cache_linedirty(cp[2], 0x12345000, 0x8), 1 ); - printf("Checking Dirty Vector %x, Result = %d (Expect %d)\n", 0x9, - shd_cache_linedirty(cp[2], 0x12345000, 0x9), 1 ); - -} - -#endif diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h index d07d1e1..3b4bf73 100644 --- a/src/gpgpu-sim/gpu-cache.h +++ b/src/gpgpu-sim/gpu-cache.h @@ -71,22 +71,22 @@ #ifndef GPU_CACHE_H #define GPU_CACHE_H -#define VALID 0x01 -#define DIRTY 0x02 -#define RESERVED 0x04 +#define VALID 0x01 // block is valid (and present in cache) +#define DIRTY 0x02 // block is dirty +#define RESERVED 0x04 // there is an outstanding request for this block, but it has not returned yet enum cache_request_status { HIT, - HIT_W_WT, /* Hit, but write through cache, still needs to send to memory */ - MISS_NO_WB, /* miss, but witeback not necessary*/ - MISS_W_WB, /* miss, must do writeback */ - WB_HIT_ON_MISS, /* request hit on a reservation in wb cache*/ + HIT_W_WT, // Hit, but write through cache, still needs to send to memory + MISS_NO_WB, // miss, but witeback not necessary + MISS_W_WB, // miss, must do writeback + WB_HIT_ON_MISS, // request hit on a reservation in wb cache RESERVATION_FAIL, NUM_CACHE_REQUEST_STATUS }; -typedef struct { +struct shd_cache_line_t { unsigned long long int tag; unsigned long long int addr; unsigned int set; @@ -94,7 +94,7 @@ typedef struct { unsigned int fetch_time; unsigned int last_used; unsigned char status; /* valid, dirty... etc */ -} shd_cache_line_t; +}; #define LRU 'L' @@ -107,7 +107,7 @@ enum cache_write_policy{ write_through //reservation based, use much handle reservation full error. }; -typedef struct { +struct shd_cache_t { char *name; @@ -135,13 +135,10 @@ typedef struct { unsigned long long int bank_mask; -} shd_cache_t; +}; -shd_cache_t * shd_cache_create( char *name, - unsigned int nset, - unsigned int assoc, - unsigned int line_sz, - unsigned char policy, +shd_cache_t * shd_cache_create( const char *name, + const char *opt, unsigned int hit_latency, unsigned long long int bank_mask, enum cache_write_policy wp); @@ -151,15 +148,14 @@ void shd_cache_destroy( shd_cache_t* cp ); // hook up with shader core logger void shd_cache_bind_logger(shd_cache_t* cp, int core_id, int type_id); -//depercated, use _wb +// depricated use shd_cache_access_new shd_cache_line_t* shd_cache_access( shd_cache_t *cp, unsigned long long int addr, unsigned int nbytes, unsigned char write, unsigned int sim_cycle ); -//cache check checks for wb and forwards information over. -enum cache_request_status shd_cache_access_wb( shd_cache_t *cp, +enum cache_request_status shd_cache_access_new( shd_cache_t *cp, unsigned long long int addr, unsigned int nbytes, unsigned char write, @@ -185,7 +181,7 @@ unsigned long long int L2_shd_cache_fill( shd_cache_t *cp, unsigned long long int addr, unsigned int sim_cycle ); -void shd_cache_print( shd_cache_t *cp, FILE *stream); +void shd_cache_print( const shd_cache_t *cp, FILE *stream, unsigned &total_access, unsigned &total_misses ); float shd_cache_windowed_cache_miss_rate(shd_cache_t*, int); void shd_cache_new_window(shd_cache_t*); diff --git a/src/gpgpu-sim/gpu-misc.h b/src/gpgpu-sim/gpu-misc.h index 3b3cb4c..ffe316b 100644 --- a/src/gpgpu-sim/gpu-misc.h +++ b/src/gpgpu-sim/gpu-misc.h @@ -70,9 +70,9 @@ #define CONSTC 100 #define DCACHE 200 #define TEXTC 300 -#define SHD_CACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->L1cache->line_sz - 1))) -#define SHD_TEXCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->L1texcache->line_sz - 1))) -#define SHD_CONSTCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->L1constcache->line_sz - 1))) +#define SHD_CACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->m_L1D->line_sz - 1))) +#define SHD_TEXCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->m_L1T->line_sz - 1))) +#define SHD_CONSTCACHE_TAG(x,shdr) ((x) & (~((unsigned long long int)shdr->m_L1C->line_sz - 1))) #define CACHE_TAG_OF(x,cache) ((x) & (~((unsigned long long int)cache->line_sz - 1))) #define CACHE_TAG_OF_64(x) ((x) & (~((unsigned long long int)64 - 1))) diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index b5527e1..8114b9e 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -91,18 +91,19 @@ #include "../cuda-sim/ptx-stats.h" #include "../intersim/statwraper.h" +#include "../intersim/interconnect_interface.h" #include "../abstract_hardware_model.h" #include "../debug.h" #include "../gpgpusim_entrypoint.h" #include "../cuda-sim/cuda-sim.h" #include "mem_latency_stat.h" +#include "visualizer.h" +#include "stats.h" #include <stdio.h> #include <string.h> -#include <queue> - #define MAX(a,b) (((a)>(b))?(a):(b)) bool g_interactive_debugger_enabled=false; @@ -115,13 +116,10 @@ unsigned freed_L2write_mfs = 0; unsigned freed_dummy_read_mfs = 0; unsigned long long gpu_sim_cycle = 0; unsigned long long gpu_sim_insn = 0; -unsigned long long gpu_sim_insn_no_ld_const = 0; unsigned long long gpu_sim_prev_insn = 0; -unsigned long long gpu_sim_insn_last_update = 0; unsigned long long gpu_tot_sim_cycle = 0; unsigned long long gpu_tot_sim_insn = 0; unsigned long long gpu_last_sim_cycle = 0; -unsigned long long gpu_completed_thread = 0; unsigned long long gpu_tot_issued_cta = 0; unsigned long long gpu_tot_completed_thread = 0; @@ -130,27 +128,17 @@ unsigned int **num_activates; //num_activates[dram chip id][bank id] unsigned int **row_access; //row_access[dram chip id][bank id] unsigned int **max_conc_access2samerow; //max_conc_access2samerow[dram chip id][bank id] unsigned int **max_servicetime2samerow; //max_servicetime2samerow[dram chip id][bank id] -unsigned int L1_read_miss = 0; -unsigned int L1_write_miss = 0; -unsigned int L1_write_hit_on_miss = 0; -unsigned int L1_writeback = 0; -unsigned int L1_texture_miss = 0; -unsigned int L1_const_miss = 0; unsigned int gpgpu_n_sent_writes = 0; unsigned int gpgpu_n_processed_writes = 0; -unsigned int *max_return_queue_length; // performance counter for stalls due to congestion. -unsigned int gpu_stall_shd_mem = 0; unsigned int gpu_stall_wr_back = 0; unsigned int gpu_stall_dramfull = 0; unsigned int gpu_stall_icnt2sh = 0; -unsigned int gpu_stall_by_MSHRwb = 0; //shader cannot send to icnt because icnt buffer is full //Note: it is accumulative for all shaders and is never reset //so it might increase 8 times in a cycle if we have 8 shaders -unsigned int gpu_stall_sh2icnt = 0; char *gpgpu_runtime_stat; int gpu_stat_sample_freq = 10000; int gpu_runtime_stat_flag = 0; @@ -160,7 +148,6 @@ unsigned long long gpu_max_insn = 0; int gpu_deadlock = 0; unsigned g_next_mf_request_uid = 1; static unsigned long long last_gpu_sim_insn = 0; -int g_nthreads_issued; int g_total_cta_left; // GPGPU-Sim timing model options @@ -168,34 +155,12 @@ int gpu_max_cycle_opt; int gpu_max_insn_opt; int gpu_max_cta_opt; bool gpu_deadlock_detect; -int gpgpu_simd_model; -enum dram_ctrl_t gpgpu_dram_scheduler; -bool gpgpu_no_dl1; -char *gpgpu_cache_texl1_opt; -char *gpgpu_cache_constl1_opt; -char *gpgpu_cache_dl1_opt; -char *gpgpu_cache_dl2_opt; -int gpgpu_partial_write_mask; -bool gpgpu_perfect_mem; char *gpgpu_shader_core_pipeline_opt; -unsigned int gpgpu_dram_buswidth; -unsigned int gpgpu_dram_burst_length; int gpgpu_dram_sched_queue_size; -char *gpgpu_dram_timing_opt; bool gpgpu_flush_cache; int gpgpu_mem_address_mask; int gpgpu_cflog_interval; -void ptx_dump_regs( void *thd ); -unsigned ptx_kernel_program_size(); -void visualizer_printstat(); -void time_vector_create(int ld_size,int st_size); -void time_vector_print(void); -void time_vector_update(unsigned int uid,int slot ,long int cycle,int type); -void node_req_hist_clear(void *p); -void node_req_hist_dump(void *p); -void node_req_hist_update(void * p,int node, long long cycle); - /* Defining Clock Domains basically just the ratio is important */ @@ -204,114 +169,34 @@ basically just the ratio is important */ #define DRAM 0x04 #define ICNT 0x08 -double core_time=0; -double icnt_time=0; -double dram_time=0; -double l2_time=0; - -double core_freq=2 MhZ; -double icnt_freq=2 MhZ; -double dram_freq=2 MhZ; -double l2_freq=2 MhZ; - -double core_period = 1 /( 2 MhZ); -double icnt_period = 1 /( 2 MhZ); -double dram_period = 1 /( 2 MhZ); -double l2_period = 1 / (2 MhZ); char * gpgpu_clock_domains; /* GPU uArch parameters */ -unsigned int gpu_n_mem; -unsigned int gpu_mem_n_bk; unsigned int gpu_n_mem_per_ctrlr; -unsigned int gpu_n_shader; -int gpu_concentration; int gpu_n_tpc; -unsigned int gpu_n_mshr_per_shader; -unsigned int gpu_n_thread_per_shader; -unsigned int gpu_n_warp_per_shader; -unsigned int gpu_n_mshr_per_thread = 1; -bool gpgpu_reg_bankconflict; -bool gpgpu_operand_collector; -int gpgpu_operand_collector_num_units; -int gpgpu_operand_collector_num_units_sfu; -unsigned int gpgpu_pre_mem_stages; -bool gpgpu_no_divg_load; char *gpgpu_dwf_hw_opt; bool gpgpu_thread_swizzling; -bool gpgpu_strict_simd_wrbk; -int pdom_sched_type; -int n_pdom_sc_orig_stat = 0; //the selected pdom schedular is used -int n_pdom_sc_single_stat = 0; //only a single warp is ready to go in that cycle. -int *num_warps_issuable; -int *num_warps_issuable_pershader; -bool gpgpu_cuda_sim; -bool gpgpu_spread_blocks_across_cores; -bool gpgpu_stall_on_use; -shader_core_ctx_t **sc; -dram_t **dram; -unsigned int common_clock = 0; unsigned int more_thread = 1; -unsigned int warp_conflict_at_writeback = 0; -unsigned int gpgpu_commit_pc_beyond_two = 0; -bool gpgpu_cache_wt_through; - -//memory access classification -int gpgpu_n_mem_read_local = 0; -int gpgpu_n_mem_write_local = 0; -int gpgpu_n_mem_texture = 0; -int gpgpu_n_mem_const = 0; -int gpgpu_n_mem_read_global = 0; -int gpgpu_n_mem_write_global = 0; #define MEM_LATENCY_STAT_IMPL #include "mem_latency_stat.h" -unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid ); -unsigned char fq_push(unsigned long long int addr, int bsize, unsigned char write, partial_write_mask_t partial_write_mask, - int sid, int wid, mshr_entry* mshr, int cache_hits_waiting, - enum mem_access_type mem_acc, address_type pc); -int issue_mf_from_fq(mem_fetch_t *mf); -unsigned char single_check_icnt_has_buffer(int chip, int sid, unsigned char is_write ); -unsigned char fq_pop(int tpc_id); -void fill_shd_L1_with_new_line(shader_core_ctx_t * sc, mem_fetch_t * mf); - -void set_param_gpgpu_num_shaders(int num_shaders); -unsigned ptx_sim_grid_size(); -void icnt_init_grid(); -void interconnect_stats(); -void icnt_overal_stat(); -void gpu_sim_loop( int grid_num ); -void print_shader_cycle_distro( FILE *fout ) ; -void find_reconvergence_points(); -void dwf_process_reconv_pts(); - int g_ptx_inst_debug_to_file; char* g_ptx_inst_debug_file; int g_ptx_inst_debug_thread_uid; -#define CREATELOG 111 -#define SAMPLELOG 222 -#define DUMPLOG 333 -void L2c_log(int task); -void dram_log(int task); - -// DRAM delay queue and memory_fetch container -// A delay queue for each mem - vector of queues -struct dram_delay_t{ - unsigned long long ready_cycle; - mem_fetch_t* mf; -}; -std::vector< std::queue<dram_delay_t> > dram_delay_queues; +int g_ptx_convert_to_ptxplus; +int g_ptx_save_converted_ptxplus; void visualizer_options(option_parser_t opp); -void gpu_reg_options(option_parser_t opp) + +void gpgpu_sim::reg_options(option_parser_t opp) { - option_parser_register(opp, "-gpgpu_simd_model", OPT_INT32, &gpgpu_simd_model, + option_parser_register(opp, "-gpgpu_simd_model", OPT_INT32, &m_shader_config->model, "0 = no recombination, 1 = post-dominator, 2 = MIMD, 3 = dynamic warp formation", "0"); - option_parser_register(opp, "-gpgpu_dram_scheduler", OPT_INT32, &gpgpu_dram_scheduler, - "0 = fifo (default), 1 = fast ideal", "0"); + option_parser_register(opp, "-gpgpu_dram_scheduler", OPT_INT32, &m_memory_config->scheduler_type, + "0 = fifo, 1 = FR-FCFS (defaul)", "1"); option_parser_register(opp, "-gpgpu_max_cycle", OPT_INT32, &gpu_max_cycle_opt, "terminates gpu simulation early (0 = no limit)", @@ -323,46 +208,54 @@ void gpu_reg_options(option_parser_t opp) "terminates gpu simulation early (0 = no limit)", "0"); - option_parser_register(opp, "-gpgpu_tex_cache:l1", OPT_CSTR, &gpgpu_cache_texl1_opt, + option_parser_register(opp, "-gpgpu_tex_cache:l1", OPT_CSTR, &m_shader_config->gpgpu_cache_texl1_opt, "per-shader L1 texture cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}", "512:64:2:L"); - option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &gpgpu_cache_constl1_opt, + option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &m_shader_config->gpgpu_cache_constl1_opt, "per-shader L1 constant memory cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}", "64:64:2:L"); - option_parser_register(opp, "-gpgpu_no_dl1", OPT_BOOL, &gpgpu_no_dl1, + option_parser_register(opp, "-gpgpu_no_dl1", OPT_BOOL, &m_shader_config->gpgpu_no_dl1, "no dl1 cache (voids -gpgpu_cache:dl1 option)", "0"); - option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &gpgpu_cache_dl1_opt, + option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &m_shader_config->gpgpu_cache_dl1_opt, "shader L1 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}", "256:128:1:L"); - option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &gpgpu_cache_dl2_opt, + option_parser_register(opp, "-gpgpu_cache:il1", OPT_CSTR, &m_shader_config->gpgpu_cache_il1_opt, + "shader L1 instruction cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}", + "4:256:4:L"); + + option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &m_memory_config->gpgpu_cache_dl2_opt, "unified banked L2 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}; disabled by default", NULL); - option_parser_register(opp, "-gpgpu_perfect_mem", OPT_BOOL, &gpgpu_perfect_mem, + option_parser_register(opp, "-gpgpu_perfect_mem", OPT_BOOL, &m_shader_config->gpgpu_perfect_mem, "enable perfect memory mode (no cache miss)", "0"); + option_parser_register(opp, "-gpgpu_sm_uarch", OPT_CSTR, &m_shader_config->pipeline_model, + "shader core uarch model [GPGPUSIM_ORIG,GT200] (default=GPGPUSIM_ORIG)", + "GPGPUSIM_ORIG"); + option_parser_register(opp, "-gpgpu_shader_core_pipeline", OPT_CSTR, &gpgpu_shader_core_pipeline_opt, "shader core pipeline config, i.e., {<nthread>:<warpsize>:<pipe_simd_width>}", "256:32:32"); - option_parser_register(opp, "-gpgpu_shader_registers", OPT_UINT32, &gpgpu_shader_registers, + option_parser_register(opp, "-gpgpu_shader_registers", OPT_UINT32, &m_shader_config->gpgpu_shader_registers, "Number of registers per shader core. Limits number of concurrent CTAs. (default 8192)", "8192"); - option_parser_register(opp, "-gpgpu_shader_cta", OPT_UINT32, &gpgpu_shader_cta, + option_parser_register(opp, "-gpgpu_shader_cta", OPT_UINT32, &m_shader_config->max_cta_per_core, "Maximum number of concurrent CTAs in shader (default 8)", "8"); - option_parser_register(opp, "-gpgpu_n_shader", OPT_UINT32, &gpu_n_shader, + option_parser_register(opp, "-gpgpu_n_shader", OPT_UINT32, &m_n_shader, "number of shaders in gpu", "8"); - option_parser_register(opp, "-gpgpu_n_mem", OPT_UINT32, &gpu_n_mem, + option_parser_register(opp, "-gpgpu_n_mem", OPT_UINT32, &m_n_mem, "number of memory modules (e.g. memory controllers) in gpu", "8"); option_parser_register(opp, "-gpgpu_n_mem_per_ctrlr", OPT_UINT32, &gpu_n_mem_per_ctrlr, @@ -376,39 +269,39 @@ void gpu_reg_options(option_parser_t opp) "DWF scheduling heuristic: 0 = majority, 1 = minority, 2 = timestamp, 3 = pdom priority, 4 = pc-based, 5 = max-heap", "0"); - option_parser_register(opp, "-gpgpu_reg_bankconflict", OPT_BOOL, &gpgpu_reg_bankconflict, - "Check for bank conflict in the pipeline", + option_parser_register(opp, "-gpgpu_dwf_reg_bankconflict", OPT_BOOL, &m_shader_config->gpgpu_dwf_reg_bankconflict, + "bank conflict model used in MICRO'07/TACO'09 work (default=disabled)", "0"); option_parser_register(opp, "-gpgpu_dwf_regbk", OPT_BOOL, &gpgpu_dwf_regbk, "Have dwf scheduler to avoid bank conflict", "1"); - option_parser_register(opp, "-gpgpu_memlatency_stat", OPT_INT32, &gpgpu_memlatency_stat, + option_parser_register(opp, "-gpgpu_memlatency_stat", OPT_INT32, &m_memory_config->gpgpu_memlatency_stat, "track and display latency statistics 0x2 enables MC, 0x4 enables queue logs", "0"); - option_parser_register(opp, "-gpu_n_mshr_per_shader", OPT_UINT32, &gpu_n_mshr_per_shader, + option_parser_register(opp, "-gpu_n_mshr_per_shader", OPT_UINT32, &m_shader_config->n_mshr_per_shader, "Number of MSHRs per shader", "64"); - option_parser_register(opp, "-gpgpu_interwarp_mshr_merge", OPT_INT32, &gpgpu_interwarp_mshr_merge, + option_parser_register(opp, "-gpgpu_interwarp_mshr_merge", OPT_INT32, &m_shader_config->gpgpu_interwarp_mshr_merge, "interwarp coalescing", "0"); - option_parser_register(opp, "-gpgpu_dram_sched_queue_size", OPT_INT32, &gpgpu_dram_sched_queue_size, + option_parser_register(opp, "-gpgpu_dram_sched_queue_size", OPT_INT32, &m_memory_config->gpgpu_dram_sched_queue_size, "0 = unlimited (default); # entries per chip", "0"); - option_parser_register(opp, "-gpgpu_dram_buswidth", OPT_UINT32, &gpgpu_dram_buswidth, + option_parser_register(opp, "-gpgpu_dram_buswidth", OPT_UINT32, &m_memory_config->gpgpu_dram_buswidth, "default = 4 bytes (8 bytes per cycle at DDR)", "4"); - option_parser_register(opp, "-gpgpu_dram_burst_length", OPT_UINT32, &gpgpu_dram_burst_length, + option_parser_register(opp, "-gpgpu_dram_burst_length", OPT_UINT32, &m_memory_config->gpgpu_dram_burst_length, "Burst length of each DRAM request (default = 4 DDR cycle)", "4"); - option_parser_register(opp, "-gpgpu_dram_timing_opt", OPT_CSTR, &gpgpu_dram_timing_opt, + option_parser_register(opp, "-gpgpu_dram_timing_opt", OPT_CSTR, &m_memory_config->gpgpu_dram_timing_opt, "DRAM timing parameters = {nbk:tCCD:tRRD:tRCD:tRAS:tRP:tRC:CL:WL:tWTR}", "4:2:8:12:21:13:34:9:4:5"); @@ -421,13 +314,13 @@ void gpu_reg_options(option_parser_t opp) "Flush cache at the end of each kernel call", "0"); - option_parser_register(opp, "-gpgpu_pre_mem_stages", OPT_UINT32, &gpgpu_pre_mem_stages, + option_parser_register(opp, "-gpgpu_pre_mem_stages", OPT_UINT32, &m_shader_config->gpgpu_pre_mem_stages, "default = 0 pre-memory pipeline stages", "0"); - option_parser_register(opp, "-gpgpu_no_divg_load", OPT_BOOL, &gpgpu_no_divg_load, - "Don't allow divergence on load", - "0"); + option_parser_register(opp, "-gpgpu_no_divg_load", OPT_BOOL, &m_shader_config->gpgpu_no_divg_load, + "Don't allow divergence on load (meaningful for dynamic warp formation only)", + "1"); option_parser_register(opp, "-gpgpu_dwf_hw", OPT_CSTR, &gpgpu_dwf_hw_opt, "dynamic warp formation hw config, i.e., {<#LUT_entries>:<associativity>|none}", @@ -437,23 +330,15 @@ void gpu_reg_options(option_parser_t opp) "Thread Swizzling (1=on, 0=off)", "0"); - option_parser_register(opp, "-gpgpu_strict_simd_wrbk", OPT_BOOL, &gpgpu_strict_simd_wrbk, - "Applying Strick SIMD WriteBack Stage (1=on, 0=off)", - "0"); - - option_parser_register(opp, "-gpgpu_shmem_size", OPT_UINT32, &gpgpu_shmem_size, + option_parser_register(opp, "-gpgpu_shmem_size", OPT_UINT32, &m_shader_config->gpgpu_shmem_size, "Size of shared memory per shader core (default 16kB)", "16384"); - option_parser_register(opp, "-gpgpu_shmem_bkconflict", OPT_BOOL, &gpgpu_shmem_bkconflict, - "Turn on bank conflict check for shared memory", - "0"); - - option_parser_register(opp, "-gpgpu_shmem_pipe_speedup", OPT_INT32, &gpgpu_shmem_pipe_speedup, + option_parser_register(opp, "-gpgpu_shmem_pipe_speedup", OPT_INT32, &m_shader_config->gpgpu_shmem_pipe_speedup, "Number of groups each warp is divided for shared memory bank conflict check", "2"); - option_parser_register(opp, "-gpgpu_cache_wt_through", OPT_BOOL, &gpgpu_cache_wt_through, + option_parser_register(opp, "-gpgpu_cache_wt_through", OPT_BOOL, &m_shader_config->gpgpu_cache_wt_through, "L1 cache become write through (1=on, 0=off)", "0"); @@ -461,36 +346,24 @@ void gpu_reg_options(option_parser_t opp) "Stop the simulation at deadlock (1=on (default), 0=off)", "1"); - option_parser_register(opp, "-gpgpu_cache_bkconflict", OPT_BOOL, &gpgpu_cache_bkconflict, - "Turn on bank conflict check for L1 cache access", - "0"); - - option_parser_register(opp, "-gpgpu_n_cache_bank", OPT_INT32, &gpgpu_n_cache_bank, + option_parser_register(opp, "-gpgpu_n_cache_bank", OPT_INT32, &m_shader_config->gpgpu_n_cache_bank, "Number of banks in L1 cache, also for memory coalescing stall", "1"); - option_parser_register(opp, "-gpgpu_warpdistro_shader", OPT_INT32, &gpgpu_warpdistro_shader, + option_parser_register(opp, "-gpgpu_warpdistro_shader", OPT_INT32, &m_shader_config->gpgpu_warpdistro_shader, "Specify which shader core to collect the warp size distribution from", "-1"); - option_parser_register(opp, "-gpgpu_pdom_sched_type", OPT_INT32, &pdom_sched_type, + option_parser_register(opp, "-gpgpu_pdom_sched_type", OPT_INT32, &m_pdom_sched_type, "0 = first ready warp found, 1 = random, 8 = loose round robin", "8"); - option_parser_register(opp, "-gpgpu_spread_blocks_across_cores", OPT_BOOL, - &gpgpu_spread_blocks_across_cores, - "Spread block-issuing across all cores instead of filling up core by core (do NOT disable)", - "1"); - option_parser_register(opp, "-gpgpu_stall_on_use", OPT_BOOL, - &gpgpu_stall_on_use, + &m_shader_config->gpgpu_stall_on_use, "Enable stall-on-use", "1"); - option_parser_register(opp, "-gpgpu_cuda_sim", OPT_BOOL, &gpgpu_cuda_sim, - "use PTX instruction set", - "1"); option_parser_register(opp, "-gpgpu_ptx_instruction_classification", OPT_INT32, &gpgpu_ptx_instruction_classification, "if enabled will classify ptx instruction types per kernel (Max 255 kernels now)", @@ -502,34 +375,28 @@ void gpu_reg_options(option_parser_t opp) "Clock Domain Frequencies in MhZ {<Core Clock>:<ICNT Clock>:<L2 Clock>:<DRAM Clock>}", "500.0:2000.0:2000.0:2000.0"); - option_parser_register(opp, "-gpgpu_shmem_port_per_bank", OPT_INT32, &gpgpu_shmem_port_per_bank, + option_parser_register(opp, "-gpgpu_shmem_port_per_bank", OPT_INT32, &m_shader_config->gpgpu_shmem_port_per_bank, "Number of access processed by a shared memory bank per cycle (default = 2)", "2"); - option_parser_register(opp, "-gpgpu_cache_port_per_bank", OPT_INT32, &gpgpu_cache_port_per_bank, + option_parser_register(opp, "-gpgpu_cache_port_per_bank", OPT_INT32, &m_shader_config->gpgpu_cache_port_per_bank, "Number of access processed by a cache bank per cycle (default = 2)", "2"); - option_parser_register(opp, "-gpgpu_const_port_per_bank", OPT_INT32, &gpgpu_const_port_per_bank, + option_parser_register(opp, "-gpgpu_const_port_per_bank", OPT_INT32, &m_shader_config->gpgpu_const_port_per_bank, "Number of access processed by a constant cache bank per cycle (default = 2)", "2"); option_parser_register(opp, "-gpgpu_cflog_interval", OPT_INT32, &gpgpu_cflog_interval, "Interval between each snapshot in control flow logger", "0"); - option_parser_register(opp, "-gpgpu_partial_write_mask", OPT_INT32, &gpgpu_partial_write_mask, - "use partial write mask to filter memory requests <1>No extra reads(use this!)<2>extra reads generated for partial chunks", - "0"); option_parser_register(opp, "-gpu_concentration", OPT_INT32, &gpu_concentration, "Number of shader cores per interconnection port (default = 1)", "1"); - option_parser_register(opp, "-gpgpu_local_mem_map", OPT_INT32, &gpgpu_local_mem_map, - "Mapping from local memory space address to simulated GPU physical address space (default = 1)", + option_parser_register(opp, "-gpgpu_local_mem_map", OPT_BOOL, &m_shader_config->gpgpu_local_mem_map, + "Mapping from local memory space address to simulated GPU physical address space (default = enabled)", "1"); - option_parser_register(opp, "-gpgpu_reg_bank_conflict_model", OPT_BOOL, &gpgpu_reg_bank_conflict_model, - "Turn on register bank conflict model (default = off)", - "0"); - option_parser_register(opp, "-gpgpu_num_reg_banks", OPT_INT32, &gpgpu_num_reg_banks, + option_parser_register(opp, "-gpgpu_num_reg_banks", OPT_INT32, &m_shader_config->gpgpu_num_reg_banks, "Number of register banks (default = 8)", "8"); - option_parser_register(opp, "-gpgpu_reg_bank_use_warp_id", OPT_BOOL, &gpgpu_reg_bank_use_warp_id, + option_parser_register(opp, "-gpgpu_reg_bank_use_warp_id", OPT_BOOL, &m_shader_config->gpgpu_reg_bank_use_warp_id, "Use warp ID in mapping registers to banks (default = off)", "0"); option_parser_register(opp, "-gpgpu_ptx_inst_debug_to_file", OPT_BOOL, @@ -542,135 +409,221 @@ void gpu_reg_options(option_parser_t opp) option_parser_register(opp, "-gpgpu_ptx_inst_debug_thread_uid", OPT_INT32, &g_ptx_inst_debug_thread_uid, "Thread UID for executed instructions' debug output", "1"); - option_parser_register(opp, "-gpgpu_operand_collector", OPT_BOOL, &gpgpu_operand_collector, + option_parser_register(opp, "-gpgpu_ptx_convert_to_ptxplus", OPT_BOOL, + &g_ptx_convert_to_ptxplus, + "Convert embedded ptx to ptxplus", + "0"); + option_parser_register(opp, "-gpgpu_ptx_save_converted_ptxplus", OPT_BOOL, + &g_ptx_save_converted_ptxplus, + "Saved converted ptxplus to a file", + "0"); + option_parser_register(opp, "-gpgpu_operand_collector", OPT_BOOL, &m_shader_config->gpgpu_operand_collector, "Enable operand collector model (default = off)", "0"); - option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &gpgpu_operand_collector_num_units, + option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units, "number of collecture units (default = 4)", "4"); - option_parser_register(opp, "-gpgpu_operand_collector_num_units_sfu", OPT_INT32, &gpgpu_operand_collector_num_units_sfu, + option_parser_register(opp, "-gpgpu_operand_collector_num_units_sfu", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units_sfu, "number of collecture units (default = 4)", "4"); - option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &gpgpu_coalesce_arch, + option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &m_shader_config->gpgpu_coalesce_arch, "Coalescing arch (default = 13, anything else is off for now)", "13"); addrdec_setoption(opp); L2c_options(opp); visualizer_options(opp); ptx_file_line_stats_options(opp); + + m_options_set = true; } ///////////////////////////////////////////////////////////////////////////// -inline int mem2device(int memid) { +int mem2device(int memid) +{ return memid + gpu_n_tpc; } ///////////////////////////////////////////////////////////////////////////// +void increment_x_then_y_then_z( dim3 &i, const dim3 &bound) +{ + i.x++; + if ( i.x >= bound.x ) { + i.x = 0; + i.y++; + if ( i.y >= bound.y ) { + i.y = 0; + if( i.z < bound.z ) + i.z++; + } + } +} + + +void gpgpu_sim::launch( kernel_info_t &kinfo ) +{ + unsigned cta_size = kinfo.threads_per_cta(); + if ( cta_size > m_shader_config->n_thread_per_shader ) { + printf("Execution error: Shader kernel CTA (block) size is too large for microarch config.\n"); + printf(" CTA size (x*y*z) = %u, max supported = %u\n", cta_size, + m_shader_config->n_thread_per_shader ); + printf(" => either change -gpgpu_shader argument in gpgpusim.config file or\n"); + printf(" modify the CUDA source to decrease the kernel block size.\n"); + abort(); + } + + m_running_kernels.push_back(kinfo); +} -/* Allocate memory for uArch structures */ -void init_gpu () +void gpgpu_sim::next_grid( unsigned &grid_num, class function_info *&entry ) +{ + grid_num = ++m_grid_num; + m_the_kernel = m_running_kernels.front(); + m_running_kernels.pop_front(); + entry = m_the_kernel.entry(); +} + +gpgpu_sim::gpgpu_sim() { - // initialize the GPU microarchitecture model - int i; + m_options_set=false; + m_grid_num=0; + m_shader_config = (shader_core_config*)calloc(1,sizeof(shader_core_config)); + m_shader_stats = (shader_core_stats*)calloc(1,sizeof(shader_core_stats)); + m_memory_config = (memory_config*)calloc(1,sizeof(memory_config)); + m_memory_stats = NULL; +} +void set_ptx_warp_size(unsigned warp_size); + +void gpgpu_sim::init_gpu() +{ + assert( m_options_set ); + gpu_max_cycle = gpu_max_cycle_opt; - gpu_max_insn = gpu_max_insn_opt; + gpu_max_insn = gpu_max_insn_opt; - i = sscanf(gpgpu_shader_core_pipeline_opt,"%d:%d:%d", - &gpu_n_thread_per_shader, &warp_size, &pipe_simd_width); - gpu_n_warp_per_shader = gpu_n_thread_per_shader / warp_size; - num_warps_issuable = (int*) calloc(gpu_n_warp_per_shader+1, sizeof(int)); - num_warps_issuable_pershader = (int*) calloc(gpu_n_shader, sizeof(int)); - if (i == 2) { - pipe_simd_width = warp_size; - } else if (i == 3) { - assert(warp_size % pipe_simd_width == 0); + int ntok = sscanf(gpgpu_shader_core_pipeline_opt,"%d:%d", + &m_shader_config->n_thread_per_shader, + &m_shader_config->warp_size); + set_ptx_warp_size(m_shader_config->warp_size); + + m_shader_config->max_warps_per_shader = m_shader_config->n_thread_per_shader/m_shader_config->warp_size; + assert( !(m_shader_config->n_thread_per_shader % m_shader_config->warp_size) ); + + m_shader_stats->num_warps_issuable = (int*) calloc(m_shader_config->max_warps_per_shader+1, sizeof(int)); + m_shader_stats->num_warps_issuable_pershader = (int*) calloc(m_n_shader, sizeof(int)); + m_shader_stats->shader_cycle_distro = (unsigned int*) calloc(m_shader_config->warp_size + 3, sizeof(unsigned int)); + + if(ntok != 2) { + printf("GPGPU-Sim uArch: error while parsing configuration string gpgpu_shader_core_pipeline_opt\n"); + abort(); } - sscanf(gpgpu_runtime_stat, "%d:%x", - &gpu_stat_sample_freq, &gpu_runtime_stat_flag); + sscanf(gpgpu_runtime_stat, "%d:%x", &gpu_stat_sample_freq, &gpu_runtime_stat_flag); + + m_shader_config->pdom_sched_type = m_pdom_sched_type; + m_shader_config->gpgpu_n_shmem_bank=16; - sc = (shader_core_ctx_t**) calloc(gpu_n_shader, sizeof(shader_core_ctx_t*)); - int mshr_que = gpu_n_mshr_per_thread; - for (i=0;(unsigned)i<gpu_n_shader;i++) { - sc[i] = shader_create("sh", i, /* shader id*/ - gpu_n_thread_per_shader, /* number of threads */ - mshr_que, /* number of MSHR per threads */ - fq_push, fq_has_buffer, gpgpu_simd_model); + m_sc = (shader_core_ctx**) calloc(m_n_shader, sizeof(shader_core_ctx*)); + for (unsigned i=0;i<m_n_shader;i++) { + m_sc[i] = (shader_core_ctx*)calloc(sizeof(shader_core_ctx),1); + m_sc[i] = new (m_sc[i]) shader_core_ctx(this,"sh",i,i/gpu_concentration,m_shader_config,m_shader_stats); } - ptx_file_line_stats_create_exposed_latency_tracker(gpu_n_shader); + ptx_file_line_stats_create_exposed_latency_tracker(m_n_shader); // initialize dynamic warp formation scheduler int dwf_lut_size, dwf_lut_assoc; sscanf(gpgpu_dwf_hw_opt,"%d:%d", &dwf_lut_size, &dwf_lut_assoc); char *dwf_hw_policy_opt = strchr(gpgpu_dwf_hw_opt, ';'); int insn_size = 1; // for cuda-sim - create_dwf_schedulers(gpu_n_shader, dwf_lut_size, dwf_lut_assoc, - warp_size, pipe_simd_width, - gpu_n_thread_per_shader, insn_size, + create_dwf_schedulers(m_n_shader, dwf_lut_size, dwf_lut_assoc, + m_shader_config->warp_size, m_shader_config->warp_size, + m_shader_config->n_thread_per_shader, insn_size, gpgpu_dwf_heuristic, dwf_hw_policy_opt ); - gpgpu_no_divg_load = gpgpu_no_divg_load && (gpgpu_simd_model == DWF); - // always use no diverge on load for PDOM and NAIVE - gpgpu_no_divg_load = gpgpu_no_divg_load || (gpgpu_simd_model == POST_DOMINATOR || gpgpu_simd_model == NO_RECONVERGE); - if (gpgpu_no_divg_load) { - //init_warp_tracker(); - printf("warp_tracker_pool size = %d\n", get_warp_tracker_pool().size()); - } + // always use no diverge on load for stack based SIMT execution (PDOM) + m_shader_config->gpgpu_no_divg_load = (m_shader_config->model != DWF) || + (m_shader_config->gpgpu_no_divg_load && (m_shader_config->model == DWF)); + m_shader_config->m_using_dwf_rrstage = (m_shader_config->model == DWF); + m_shader_config->using_commit_queue = (m_shader_config->model == DWF || m_shader_config->model == POST_DOMINATOR); - assert(gpu_n_shader % gpu_concentration == 0); - gpu_n_tpc = gpu_n_shader / gpu_concentration; + m_shader_config->gpgpu_dwf_rr_stage_n_reg_banks=8; - dram = (dram_t**) calloc(gpu_n_mem, sizeof(dram_t*)); - // L2request = (mem_fetch_t**) calloc(gpu_n_mem, sizeof(mem_fetch_t*)); - addrdec_setnchip(gpu_n_mem); - unsigned int nbk,tCCD,tRRD,tRCD,tRAS,tRP,tRC,CL,WL,tWTR; - sscanf(gpgpu_dram_timing_opt,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",&nbk,&tCCD,&tRRD,&tRCD,&tRAS,&tRP,&tRC,&CL,&WL,&tWTR); - gpu_mem_n_bk = nbk; - for (i=0;(unsigned)i<gpu_n_mem;i++) { - dram[i] = dram_create(i, nbk, tCCD, tRRD, tRCD, tRAS, tRP, tRC, - CL, WL, gpgpu_dram_burst_length/*BL*/, tWTR, gpgpu_dram_buswidth/*busW*/, - gpgpu_dram_sched_queue_size, gpgpu_dram_scheduler); - if (gpgpu_cache_dl2_opt) - L2c_create(dram[i], gpgpu_cache_dl2_opt); - } - dram_log(CREATELOG); - if (gpgpu_cache_dl2_opt && 1) { - L2c_log(CREATELOG); - } - concurrent_row_access = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - num_activates = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - row_access = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - max_conc_access2samerow = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - max_servicetime2samerow = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); + assert(m_n_shader % gpu_concentration == 0); + gpu_n_tpc = m_n_shader / gpu_concentration; + + addrdec_setnchip(m_n_mem); + m_memory_partition_unit = new memory_partition_unit*[m_n_mem]; + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i] = new memory_partition_unit(i, m_memory_config); + m_memory_stats = new memory_stats_t(m_n_mem,m_n_shader,m_shader_config,m_memory_config); + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->set_stats(m_memory_stats); - for (i=0;(unsigned)i<gpu_n_mem ;i++ ) { - concurrent_row_access[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - row_access[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - num_activates[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - max_conc_access2samerow[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - max_servicetime2samerow[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); + concurrent_row_access = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*)); + num_activates = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*)); + row_access = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*)); + max_conc_access2samerow = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*)); + max_servicetime2samerow = (unsigned int**) calloc(m_n_mem, sizeof(unsigned int*)); + + for (unsigned i=0;i<m_n_mem ;i++ ) { + concurrent_row_access[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int)); + row_access[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int)); + num_activates[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int)); + max_conc_access2samerow[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int)); + max_servicetime2samerow[i] = (unsigned int*) calloc(m_memory_config->gpu_mem_n_bk, sizeof(unsigned int)); } - memlatstat_init(); + m_memory_stats = new memory_stats_t(m_n_mem,m_n_shader,m_shader_config,m_memory_config); - L2c_init_stat(); - max_return_queue_length = (unsigned int*) calloc(gpu_n_shader, sizeof(unsigned int)); - icnt_init(gpu_n_tpc, gpu_n_mem); + m_shader_stats->max_return_queue_length = (unsigned int*) calloc(m_n_shader, sizeof(unsigned int)); - common_clock = 0; + icnt_init(gpu_n_tpc, m_n_mem,m_shader_config); time_vector_create(NUM_MEM_REQ_STAT,MR_2SH_ICNT_INJECTED); + fprintf(stdout, "GPU performance model initialization complete.\n"); + init_clock_domains(); +} + +int gpgpu_sim::shared_mem_size() const +{ + return m_shader_config->gpgpu_shmem_size; +} + +int gpgpu_sim::num_registers_per_core() const +{ + return m_shader_config->gpgpu_shader_registers; } +int gpgpu_sim::wrp_size() const +{ + return m_shader_config->warp_size; +} +int gpgpu_sim::shader_clock() const +{ + return core_freq/1000; +} -void gpu_print_stat(); +void gpgpu_sim::set_prop( cudaDeviceProp *prop ) +{ + m_cuda_properties = prop; +} -void init_clock_domains(void ) { +const struct cudaDeviceProp *gpgpu_sim::get_prop() const +{ + return m_cuda_properties; +} + +enum divergence_support_t gpgpu_sim::simd_model() const +{ + return m_shader_config->model; +} + +void gpgpu_sim::init_clock_domains(void ) +{ sscanf(gpgpu_clock_domains,"%lf:%lf:%lf:%lf", &core_freq, &icnt_freq, &l2_freq, &dram_freq); core_freq = core_freq MhZ; @@ -689,22 +642,21 @@ void init_clock_domains(void ) { printf("GPGPU-Sim uArch: clock periods: %.20lf:%.20lf:%.20lf:%.20lf\n",core_period,icnt_period,l2_period,dram_period); } -void reinit_clock_domains(void) +void gpgpu_sim::reinit_clock_domains(void) { - core_time = 0 ; - dram_time = 0 ; + core_time = 0; + dram_time = 0; icnt_time = 0; l2_time = 0; } -void init_once(void ) { - init_clock_domains(); -} - // return the number of cycle required to run all the trace on the gpu -unsigned int run_gpu_sim(int grid_num) +unsigned int gpgpu_sim::run_gpu_sim() { // run a CUDA grid on the GPU microarchitecture simulator + int grid_num = m_grid_num; + kernel_info_t &entry = m_the_kernel; + size_t program_size = get_kernel_code_size(entry.entry()); int not_completed; int mem_busy; @@ -717,28 +669,17 @@ unsigned int run_gpu_sim(int grid_num) g_next_mf_request_uid = 1; more_thread = 1; gpu_sim_insn = 0; - gpu_sim_insn_no_ld_const = 0; + m_shader_stats->gpu_sim_insn_no_ld_const = 0; + m_shader_stats->gpu_completed_thread = 0; - gpu_completed_thread = 0; - - g_nthreads_issued = 0; - - static int one_time_inits_done = 0 ; - if (!one_time_inits_done ) { - init_once(); - } reinit_clock_domains(); - assert(gpgpu_spread_blocks_across_cores); // this seems to be required, so let's make it explicit - set_option_gpgpu_spread_blocks_across_cores(gpgpu_spread_blocks_across_cores); - set_param_gpgpu_num_shaders(gpu_n_shader); - for (unsigned i=0;i<gpu_n_shader;i++) { - sc[i]->not_completed = 0; - shader_reinit(sc[i],0,sc[i]->n_threads); - } + set_param_gpgpu_num_shaders(m_n_shader); + for (unsigned i=0;i<m_n_shader;i++) + m_sc[i]->reinit(0,m_shader_config->n_thread_per_shader,true); if (gpu_max_cta_opt != 0) { g_total_cta_left = gpu_max_cta_opt; } else { - g_total_cta_left = ptx_sim_grid_size(); + g_total_cta_left = m_the_kernel.num_blocks(); } if (gpu_max_cta_opt != 0) { // the maximum number of CTA has been reached, stop any further simulation @@ -756,75 +697,57 @@ unsigned int run_gpu_sim(int grid_num) // refind the diverge/reconvergence pairs dwf_reset_reconv_pt(); - find_reconvergence_points(); - - dwf_process_reconv_pts(); - dwf_reinit_schedulers(gpu_n_shader); + dwf_process_reconv_pts(entry.entry()); + dwf_reinit_schedulers(m_n_shader); // initialize the control-flow, memory access, memory latency logger - create_thread_CFlogger( gpu_n_shader, gpu_n_thread_per_shader, ptx_kernel_program_size(), 0, gpgpu_cflog_interval ); - shader_CTA_count_create( gpu_n_shader, gpgpu_cflog_interval); + create_thread_CFlogger( m_n_shader, m_shader_config->n_thread_per_shader, program_size, 0, gpgpu_cflog_interval ); + shader_CTA_count_create( m_n_shader, gpgpu_cflog_interval); if (gpgpu_cflog_interval != 0) { - insn_warp_occ_create( gpu_n_shader, warp_size, ptx_kernel_program_size() ); - shader_warp_occ_create( gpu_n_shader, warp_size, gpgpu_cflog_interval); - shader_mem_acc_create( gpu_n_shader, gpu_n_mem, 4, gpgpu_cflog_interval); - shader_mem_lat_create( gpu_n_shader, gpgpu_cflog_interval); - shader_cache_access_create( gpu_n_shader, 3, gpgpu_cflog_interval); + insn_warp_occ_create( m_n_shader, m_shader_config->warp_size, program_size ); + shader_warp_occ_create( m_n_shader, m_shader_config->warp_size, gpgpu_cflog_interval); + shader_mem_acc_create( m_n_shader, m_n_mem, 4, gpgpu_cflog_interval); + shader_mem_lat_create( m_n_shader, gpgpu_cflog_interval); + shader_cache_access_create( m_n_shader, 3, gpgpu_cflog_interval); set_spill_interval (gpgpu_cflog_interval * 40); } // calcaulte the max cta count and cta size for local memory address mapping - gpu_max_cta_per_shader = max_cta_per_shader(sc[0]); + m_shader_config->gpu_max_cta_per_shader = m_sc[0]->max_cta(entry.entry()); //gpu_max_cta_per_shader is limited by number of CTAs if not enough - if (ptx_sim_grid_size() < gpu_max_cta_per_shader*gpu_n_shader) { - gpu_max_cta_per_shader = (ptx_sim_grid_size() / gpu_n_shader); - if (ptx_sim_grid_size() % gpu_n_shader) - gpu_max_cta_per_shader++; + if (m_the_kernel.num_blocks() < m_shader_config->gpu_max_cta_per_shader*m_n_shader) { + m_shader_config->gpu_max_cta_per_shader = (m_the_kernel.num_blocks() / m_n_shader); + if (m_the_kernel.num_blocks() % m_n_shader) + m_shader_config->gpu_max_cta_per_shader++; } - unsigned int gpu_cta_size = ptx_sim_cta_size(); - gpu_padded_cta_size = (gpu_cta_size%32) ? 32*((gpu_cta_size/32)+1) : gpu_cta_size; + unsigned int gpu_cta_size = m_the_kernel.threads_per_cta(); + m_shader_config->gpu_padded_cta_size = (gpu_cta_size%32) ? 32*((gpu_cta_size/32)+1) : gpu_cta_size; if (g_network_mode) { icnt_init_grid(); } - // Initialize dram delay queues - dram_delay_queues.resize(gpu_n_mem); - - last_gpu_sim_insn = 0; - // add this condition as well? (gpgpu_n_processed_writes < gpgpu_n_sent_writes) while (not_completed || mem_busy || icnt2mem_busy) { - gpu_sim_loop(grid_num); - + gpu_sim_loop(); not_completed = 0; - for (unsigned i=0;i<gpu_n_shader;i++) { - not_completed += sc[i]->not_completed; - } - // dram_busy just check the request queue length into the dram - // to make sure all the memory requests (esp the writes) are done + for (unsigned i=0;i<m_n_shader;i++) + not_completed += m_sc[i]->get_not_completed(); mem_busy = 0; - for (unsigned i=0;i<gpu_n_mem;i++) { - mem_busy += dram_busy(dram[i]); - } - // icnt to the memory should clean of any pending tranfers as well - icnt2mem_busy = icnt_busy( ); - - if (gpu_max_cycle && (gpu_tot_sim_cycle + gpu_sim_cycle) >= gpu_max_cycle) { + for (unsigned i=0;i<m_n_mem;i++) + mem_busy += m_memory_partition_unit[i]->busy(); + icnt2mem_busy = icnt_busy(); + if (gpu_max_cycle && (gpu_tot_sim_cycle + gpu_sim_cycle) >= gpu_max_cycle) break; - } - if (gpu_max_insn && (gpu_tot_sim_insn + gpu_sim_insn) >= gpu_max_insn) { + if (gpu_max_insn && (gpu_tot_sim_insn + gpu_sim_insn) >= gpu_max_insn) break; - } - if (gpu_deadlock_detect && gpu_deadlock) { + if (gpu_deadlock_detect && gpu_deadlock) break; - } - } - memlatstat_lat_pw(); + m_memory_stats->memlatstat_lat_pw(m_n_shader,m_shader_config->n_thread_per_shader,m_shader_config->warp_size); gpu_tot_sim_cycle += gpu_sim_cycle; gpu_tot_sim_insn += gpu_sim_insn; - gpu_tot_completed_thread += gpu_completed_thread; + gpu_tot_completed_thread += m_shader_stats->gpu_completed_thread; ptx_file_line_stats_write_file(); @@ -836,37 +759,60 @@ unsigned int run_gpu_sim(int grid_num) icnt_overal_stat(); printf("----------------------------END-of-Interconnect-DETAILS-------------------------" ); } - if (gpgpu_memlatency_stat & GPU_MEMLATSTAT_QUEUELOGS ) { - dramqueue_latency_log_dump(); - dram_log(DUMPLOG); - if (gpgpu_cache_dl2_opt) { - L2c_log(DUMPLOG); + if (m_memory_config->gpgpu_memlatency_stat & GPU_MEMLATSTAT_QUEUELOGS ) { + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->queue_latency_log_dump(stdout); + if (m_memory_config->gpgpu_cache_dl2_opt) { + for(unsigned i=0; i<m_n_mem; i++) + m_memory_partition_unit[i]->L2c_log(DUMPLOG); L2c_latency_log_dump(); } } -#define DEADLOCK 0 if (gpu_deadlock_detect && gpu_deadlock) { fflush(stdout); printf("GPGPU-Sim uArch: ERROR ** deadlock detected: last writeback @ gpu_sim_cycle %u (+ gpu_tot_sim_cycle %u) (%u cycles ago)\n", (unsigned) gpu_sim_insn_last_update, (unsigned) (gpu_tot_sim_cycle-gpu_sim_cycle), (unsigned) (gpu_sim_cycle - gpu_sim_insn_last_update )); + unsigned num_cores=0; + for (unsigned i=0;i<m_n_shader;i++) { + unsigned not_completed = m_sc[i]->get_not_completed(); + if( not_completed ) { + if ( !num_cores ) { + printf("GPGPU-Sim uArch: DEADLOCK shader cores no longer committing instructions [core(# threads)]:\n" ); + printf("GPGPU-Sim uArch: DEADLOCK %u(%u)", i, not_completed); + } else if (num_cores < 8 ) { + printf(" %u(%u)", i, not_completed); + } else if (num_cores == 8 ) { + printf(" + others ... "); + } + num_cores++; + } + } + printf("\n"); + for (unsigned i=0;i<m_n_mem;i++) { + mem_busy += m_memory_partition_unit[i]->busy(); + if( mem_busy ) + printf("GPGPU-Sim uArch DEADLOCK: memory partition %u still busy\n", i); + } + if( icnt_busy() ) + printf("GPGPU-Sim uArch DEADLOCK: iterconnect contains traffic\n"); + printf("\nRe-run the simulator in gdb and use debug routines in .gdbinit to debug this\n"); fflush(stdout); - assert(DEADLOCK); + abort(); } return gpu_sim_cycle; } -void gpu_print_stat() +void gpgpu_sim::gpu_print_stat() const { unsigned i; - int j,k; printf("gpu_sim_cycle = %lld\n", gpu_sim_cycle); printf("gpu_sim_insn = %lld\n", gpu_sim_insn); - printf("gpu_sim_no_ld_const_insn = %lld\n", gpu_sim_insn_no_ld_const); + printf("gpu_sim_no_ld_const_insn = %lld\n", m_shader_stats->gpu_sim_insn_no_ld_const); printf("gpu_ipc = %12.4f\n", (float)gpu_sim_insn / gpu_sim_cycle); - printf("gpu_completed_thread = %lld\n", gpu_completed_thread); + printf("gpu_completed_thread = %lld\n", m_shader_stats->gpu_completed_thread); printf("gpu_tot_sim_cycle = %lld\n", gpu_tot_sim_cycle); printf("gpu_tot_sim_insn = %lld\n", gpu_tot_sim_insn); printf("gpu_tot_ipc = %12.4f\n", (float)gpu_tot_sim_insn / gpu_tot_sim_cycle); @@ -876,32 +822,29 @@ void gpu_print_stat() printf("gpgpu_n_processed_writes = %d\n", gpgpu_n_processed_writes); // performance counter for stalls due to congestion. - printf("gpu_stall_by_MSHRwb= %d\n", gpu_stall_by_MSHRwb); - printf("gpu_stall_shd_mem = %d\n", gpu_stall_shd_mem ); + printf("gpu_stall_by_MSHRwb= %d\n", m_shader_stats->gpu_stall_by_MSHRwb); + printf("gpu_stall_shd_mem = %d\n", m_shader_stats->gpu_stall_shd_mem ); printf("gpu_stall_wr_back = %d\n", gpu_stall_wr_back ); printf("gpu_stall_dramfull = %d\n", gpu_stall_dramfull); printf("gpu_stall_icnt2sh = %d\n", gpu_stall_icnt2sh ); - printf("gpu_stall_sh2icnt = %d\n", gpu_stall_sh2icnt ); + printf("gpu_stall_sh2icnt = %d\n", m_shader_stats->gpu_stall_sh2icnt ); // performance counter that are not local to one shader shader_print_accstats(stdout); - memlatstat_print(); + m_memory_stats->memlatstat_print(m_n_mem,m_memory_config->gpu_mem_n_bk); printf("max return queue length = "); - for (unsigned i=0;i<gpu_n_shader;i++) { - printf("%d ", max_return_queue_length[i]); + for (unsigned i=0;i<m_n_shader;i++) { + printf("%d ", m_shader_stats->max_return_queue_length[i]); } printf("\n"); // merge misses - printf("L1 read misses = %d\n", L1_read_miss); - printf("L1 write misses = %d\n", L1_write_miss); - printf("L1 write hit on misses = %d\n", L1_write_hit_on_miss); - printf("L1 writebacks = %d\n", L1_writeback); - printf("L1 texture misses = %d\n", L1_texture_miss); - printf("L1 const misses = %d\n", L1_const_miss); - printf("L2_write_miss = %d\n", L2_write_miss); - printf("L2_write_hit = %d\n", L2_write_hit); - printf("L2_read_miss = %d\n", L2_read_miss); - printf("L2_read_hit = %d\n", L2_read_hit); + printf("L1 read misses = %d\n", m_shader_stats->L1_read_miss); + printf("L1 write misses = %d\n", m_shader_stats->L1_write_miss); + printf("L1 write hit on misses = %d\n", m_shader_stats->L1_write_hit_on_miss); + printf("L1 writebacks = %d\n", m_shader_stats->L1_writeback); + printf("L1 texture misses = %d\n", m_shader_stats->L1_texture_miss); + printf("L1 const misses = %d\n", m_shader_stats->L1_const_miss); + m_memory_stats->print(stdout); printf("made_read_mfs = %d\n", made_read_mfs); printf("made_write_mfs = %d\n", made_write_mfs); printf("freed_read_mfs = %d\n", freed_read_mfs); @@ -909,66 +852,51 @@ void gpu_print_stat() printf("freed_L2write_mfs = %d\n", freed_L2write_mfs); printf("freed_dummy_read_mfs = %d\n", freed_dummy_read_mfs); - printf("gpgpu_n_mem_read_local = %d\n", gpgpu_n_mem_read_local); - printf("gpgpu_n_mem_write_local = %d\n", gpgpu_n_mem_write_local); - printf("gpgpu_n_mem_read_global = %d\n", gpgpu_n_mem_read_global); - printf("gpgpu_n_mem_write_global = %d\n", gpgpu_n_mem_write_global); - printf("gpgpu_n_mem_texture = %d\n", gpgpu_n_mem_texture); - printf("gpgpu_n_mem_const = %d\n", gpgpu_n_mem_const); + printf("gpgpu_n_mem_read_local = %d\n", m_shader_stats->gpgpu_n_mem_read_local); + printf("gpgpu_n_mem_write_local = %d\n", m_shader_stats->gpgpu_n_mem_write_local); + printf("gpgpu_n_mem_read_global = %d\n", m_shader_stats->gpgpu_n_mem_read_global); + printf("gpgpu_n_mem_write_global = %d\n", m_shader_stats->gpgpu_n_mem_write_global); + printf("gpgpu_n_mem_texture = %d\n", m_shader_stats->gpgpu_n_mem_texture); + printf("gpgpu_n_mem_const = %d\n", m_shader_stats->gpgpu_n_mem_const); printf("max_n_mshr_used = "); - for (unsigned i=0; i< gpu_n_shader; i++) printf("%d ", get_max_mshr_used(sc[i])); + for (unsigned i=0; i< m_n_shader; i++) printf("%d ", m_sc[i]->get_max_mshr_used() ); printf("\n"); - if (gpgpu_cache_dl2_opt) { - L2c_print_stat( ); + if (m_memory_config->gpgpu_cache_dl2_opt) { + m_memory_stats->L2c_print_stat( m_n_mem ); } - for (unsigned i=0;i<gpu_n_mem;i++) { - dram_print(dram[i],stdout); - } - - for (i=0, j=0, k=0;i<gpu_n_shader;i++) { - shd_cache_print(sc[i]->L1cache,stdout); - j+=sc[i]->L1cache->miss; - k+=sc[i]->L1cache->access; - } - printf("L1 Data Cache Total Miss Rate = %0.3f\n", (float)j/k); + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->print(stdout); - for (i=0,j=0,k=0;i<gpu_n_shader;i++) { - shd_cache_print(sc[i]->L1texcache,stdout); - j+=sc[i]->L1texcache->miss; - k+=sc[i]->L1texcache->access; - } - printf("L1 Texture Cache Total Miss Rate = %0.3f\n", (float)j/k); + unsigned a,m; + for (unsigned i=0, a=0, m=0;i<m_n_shader;i++) + m_sc[i]->L1cache_print(stdout,a,m); + printf("L1 Data Cache Total Miss Rate = %0.3f\n", (float)m/a); + for (i=0,a=0,m=0;i<m_n_shader;i++) + m_sc[i]->L1texcache_print(stdout,a,m); + printf("L1 Texture Cache Total Miss Rate = %0.3f\n", (float)m/a); + for (i=0,a=0,m=0;i<m_n_shader;i++) + m_sc[i]->L1constcache_print(stdout,a,m); + printf("L1 Const Cache Total Miss Rate = %0.3f\n", (float)m/a); - for (i=0,j=0,k=0;i<gpu_n_shader;i++) { - shd_cache_print(sc[i]->L1constcache,stdout); - j+=sc[i]->L1constcache->miss; - k+=sc[i]->L1constcache->access; - } - printf("L1 Const Cache Total Miss Rate = %0.3f\n", (float)j/k); - - if (gpgpu_cache_dl2_opt) { + if (m_memory_config->gpgpu_cache_dl2_opt) L2c_print_cache_stat(); - } printf("n_regconflict_stall = %d\n", n_regconflict_stall); - if (gpgpu_simd_model == DWF) { + if (m_shader_config->model == DWF) { dwf_print_stat(stdout); } - if (gpgpu_simd_model == POST_DOMINATOR) { + if (m_shader_config->model == POST_DOMINATOR) { printf("num_warps_issuable:"); - for (unsigned i=0;i<(gpu_n_warp_per_shader+1);i++) { - printf("%d ", num_warps_issuable[i]); + for (unsigned i=0;i<(m_shader_config->max_warps_per_shader+1);i++) { + printf("%d ", m_shader_stats->num_warps_issuable[i]); } printf("\n"); } - if (gpgpu_strict_simd_wrbk) { - printf("warp_conflict_at_writeback = %d\n", warp_conflict_at_writeback); - } - printf("gpgpu_commit_pc_beyond_two = %d\n", gpgpu_commit_pc_beyond_two); + printf("gpgpu_commit_pc_beyond_two = %d\n", m_shader_stats->gpgpu_commit_pc_beyond_two); print_shader_cycle_distro( stdout ); @@ -987,67 +915,111 @@ void gpu_print_stat() fflush(stdout); } -//////////////////////////////////////////////////////////////////////////////////// -// Wrapper function for shader cores' memory system: -//////////////////////////////////////////////////////////////////////////////////// -// a hack to make the size of a packet discrete multiples of the interconnect's flit_size. -static inline -unsigned int fill_to_next_flit(unsigned int size) +// performance counter that are not local to one shader +void gpgpu_sim::shader_print_accstats( FILE* fout ) const { - assert (g_network_mode == INTERSIM); - return size; -} + fprintf(fout, "gpgpu_n_load_insn = %d\n", m_shader_stats->gpgpu_n_load_insn); + fprintf(fout, "gpgpu_n_store_insn = %d\n", m_shader_stats->gpgpu_n_store_insn); + fprintf(fout, "gpgpu_n_shmem_insn = %d\n", m_shader_stats->gpgpu_n_shmem_insn); + fprintf(fout, "gpgpu_n_tex_insn = %d\n", m_shader_stats->gpgpu_n_tex_insn); + fprintf(fout, "gpgpu_n_const_mem_insn = %d\n", m_shader_stats->gpgpu_n_const_insn); + fprintf(fout, "gpgpu_n_param_mem_insn = %d\n", m_shader_stats->gpgpu_n_param_insn); + fprintf(fout, "gpgpu_n_shmem_bkconflict = %d\n", m_shader_stats->gpgpu_n_shmem_bkconflict); + fprintf(fout, "gpgpu_n_cache_bkconflict = %d\n", m_shader_stats->gpgpu_n_cache_bkconflict); + fprintf(fout, "gpgpu_n_intrawarp_mshr_merge = %d\n", m_shader_stats->gpgpu_n_intrawarp_mshr_merge); + fprintf(fout, "gpgpu_n_cmem_portconflict = %d\n", m_shader_stats->gpgpu_n_cmem_portconflict); -unsigned char check_icnt_has_buffer(unsigned long long int *addr, int *bsize, - int n_addr, int sid ) -{ - addrdec_t tlx; - static unsigned int *req_buffer = NULL; - //the req_buf size can be equal to gpu_n_mem ; gpu_n_shader is added to make it compatible - //with the case where a mem controller is sending to shd - if (!req_buffer) req_buffer = (unsigned int*)malloc((gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); - memset(req_buffer, 0, (gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); + fprintf(fout, "gpgpu_n_partial_writes = %d\n", m_shader_stats->gpgpu_n_partial_writes); - // aggregate all buffer requirement of all memory accesses by dram chips - for (int i=0; i< n_addr; i++) { - addrdec_tlx(addr[i],&tlx); - req_buffer[tlx.chip] += fill_to_next_flit(bsize[i]); - } + fprintf(fout, "gpgpu_stall_shd_mem[c_mem][bk_conf] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[C_MEM][BK_CONF]); + fprintf(fout, "gpgpu_stall_shd_mem[c_mem][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[C_MEM][MSHR_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[c_mem][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[C_MEM][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[t_mem][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[T_MEM][MSHR_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[t_mem][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[T_MEM][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[s_mem][bk_conf] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[S_MEM][BK_CONF]); + fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][bk_conf] = %d\n", + m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][BK_CONF] + + m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][BK_CONF] + + m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][BK_CONF] + + m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][BK_CONF] + ); // coalescing stall at data cache + fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][coal_stall] = %d\n", + m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][COAL_STALL] + + m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][COAL_STALL] + + m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][COAL_STALL] + + m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][COAL_STALL] + ); // coalescing stall + bank conflict at data cache + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][MSHR_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_CACHE_RSRV_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][MSHR_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_CACHE_RSRV_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][MSHR_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_CACHE_RSRV_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][mshr_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][MSHR_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", m_shader_stats->gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_CACHE_RSRV_FAIL]); - int tpc_id = sid / gpu_concentration; + fprintf(fout, "gpu_reg_bank_conflict_stalls = %d\n", m_shader_stats->gpu_reg_bank_conflict_stalls); +} - return icnt_has_buffer(tpc_id, req_buffer); +unsigned gpgpu_sim::threads_per_core() const +{ + return m_shader_config->n_thread_per_shader; } -unsigned char single_check_icnt_has_buffer(int chip, int sid, unsigned char is_write ) +void gpgpu_sim::mem_instruction_stats(inst_t* warp) { - static unsigned int *req_buffer = NULL; - //the req_buf size can be equal to gpu_n_mem ; gpu_n_shader is added to make it compatible - //with the case where a mem controller is sending to shd - if (!req_buffer) req_buffer = (unsigned int*)malloc((gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); - memset(req_buffer, 0, (gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); - - // aggregate all buffer requirement of all memory accesses by dram chips - - int b_size; - if (is_write) - b_size = sc[sid]->L1cache->line_sz; - else - b_size = READ_PACKET_SIZE; - req_buffer[chip] += fill_to_next_flit(b_size); - - int tpc_id = sid / gpu_concentration; - - return icnt_has_buffer(tpc_id, req_buffer); + for (unsigned i=0; i< (unsigned) m_shader_config->warp_size; i++) { + if (warp[i].hw_thread_id == -1) continue; //bubble + //this breaks some encapsulation: the is_[space] functions, if you change those, change this. + bool store = is_store(warp[i]); + switch (warp[i].space.get_type()) { + case undefined_space: + case reg_space: + break; + case shared_space: + m_shader_stats->gpgpu_n_shmem_insn++; + break; + case const_space: + m_shader_stats->gpgpu_n_const_insn++; + break; + case param_space_kernel: + case param_space_local: + m_shader_stats->gpgpu_n_param_insn++; + break; + case tex_space: + m_shader_stats->gpgpu_n_tex_insn++; + break; + case global_space: + case local_space: + if (store){ + m_shader_stats->gpgpu_n_store_insn++; + } else { + m_shader_stats->gpgpu_n_load_insn++; + } + break; + default: + abort(); + } + } } -int max_n_addr = 0; +//////////////////////////////////////////////////////////////////////////////////// +// Wrapper function for shader cores' memory system: +//////////////////////////////////////////////////////////////////////////////////// // Check the memory system for buffer availability -unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid ) +unsigned char gpgpu_sim::fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid ) { //requests should be single always now int rsize = bsize; @@ -1055,76 +1027,36 @@ unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, if (!write) { rsize = READ_PACKET_SIZE; } - return check_icnt_has_buffer(&addr, &rsize, 1, sid); + return check_icnt_has_buffer(addr, rsize, sid); } -// Takes in memory address and their parameters and pushes to the fetch queue -unsigned char fq_push(unsigned long long int addr, int bsize, unsigned char write, partial_write_mask_t partial_write_mask, - int sid, int wid, mshr_entry* mshr, int cache_hits_waiting, - enum mem_access_type mem_acc, address_type pc) +unsigned char gpgpu_sim::check_icnt_has_buffer(unsigned long long int addr, int bsize, int sid ) { - mem_fetch_t *mf; - - mf = (mem_fetch_t*) calloc(1,sizeof(mem_fetch_t)); - mf->request_uid = g_next_mf_request_uid++; - mf->addr = addr; - mf->nbytes_L1 = bsize; - mf->sid = sid; - mf->source_node = sid / gpu_concentration; - mf->wid = wid; - mf->cache_hits_waiting = cache_hits_waiting; - mf->txbytes_L1 = 0; - mf->rxbytes_L1 = 0; - mf->mshr = mshr; - if (mshr) mshr->mf = (void*)mf; // for debugging - mf->write = write; + int tpc_id = sid / gpu_concentration; + return icnt_has_buffer(tpc_id, bsize); +} - if (write) - made_write_mfs++; - else - made_read_mfs++; - memlatstat_start(mf); - addrdec_tlx(addr,&mf->tlx); - mf->bank = mf->tlx.bk; - mf->chip = mf->tlx.chip; - if (gpgpu_cache_dl2_opt) - mf->nbytes_L2 = L2c_get_linesize( dram[mf->tlx.chip] ); +unsigned gpgpu_sim::get_L2_linesize() const +{ + if (m_memory_partition_unit[0]->has_cache()) + return m_memory_partition_unit[0]->L2c_get_linesize(); else - mf->nbytes_L2 = 0; - mf->txbytes_L2 = 0; - mf->rxbytes_L2 = 0; - - mf->write_mask = partial_write_mask; - if (!write) assert(partial_write_mask == NO_PARTIAL_WRITE); - - // stat collection codes - mf->mem_acc = mem_acc; - mf->pc = pc; - - switch (mem_acc) { - case CONST_ACC_R: gpgpu_n_mem_const++; break; - case TEXTURE_ACC_R: gpgpu_n_mem_texture++; break; - case GLOBAL_ACC_R: gpgpu_n_mem_read_global++; break; - case GLOBAL_ACC_W: gpgpu_n_mem_write_global++; break; - case LOCAL_ACC_R: gpgpu_n_mem_read_local++; break; - case LOCAL_ACC_W: gpgpu_n_mem_write_local++; break; - default: assert(0); - } - - return(issue_mf_from_fq(mf)); - + return 0; } -int issue_mf_from_fq(mem_fetch_t *mf){ +int gpgpu_sim::issue_mf_from_fq(mem_fetch *mf) +{ + m_memory_stats->memlatstat_start(mf); int destination; // where is the next level of memory? destination = mf->tlx.chip; int tpc_id = mf->sid / gpu_concentration; - if (mf->mshr) mshr_update_status(mf->mshr,IN_ICNT2MEM); - if (!mf->write) { + if (mf->mshr) mf->mshr->set_status(IN_ICNT2MEM); + if (!mf->m_write) { mf->type = RD_REQ; assert( mf->timestamp == (gpu_sim_cycle+gpu_tot_sim_cycle) ); - time_vector_update(mf->mshr->insts[0].uid, MR_ICNT_PUSHED, gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ); + if( mf->mshr && mf->mshr->has_inst() ) + time_vector_update(mf->mshr->get_insts_uid(), MR_ICNT_PUSHED, gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ); icnt_push(tpc_id, mem2device(destination), (void*)mf, READ_PACKET_SIZE); } else { mf->type = WT_REQ; @@ -1137,260 +1069,235 @@ int issue_mf_from_fq(mem_fetch_t *mf){ return 0; } -inline void fill_shd_L1_with_new_line(shader_core_ctx_t * sc, mem_fetch_t * mf) { - unsigned long long int repl_addr = -1; +void shader_core_ctx::fill_shd_L1_with_new_line(mem_fetch * mf) +{ // When the data arrives, it flags all the appropriate MSHR // entries accordingly (by checking the address in each entry ) - memlatstat_read_done(mf); - - mshr_return_from_mem(sc, mf->mshr); - - if (mf->mshr->istexture) { - shd_cache_fill(sc->L1texcache,mf->addr,sc->gpu_cycle); - repl_addr = -1; - } else if (mf->mshr->isconst) { - shd_cache_fill(sc->L1constcache,mf->addr,sc->gpu_cycle); - repl_addr = -1; + if (mf->mshr->isinst()) { + shd_cache_fill(m_L1I,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle); + m_warp[mf->mshr->get_warp_id()].clear_imiss_pending(); + delete mf->mshr; + mf->mshr=NULL; } else { - if (!gpgpu_no_dl1) { - //if we are doing a writeback cache we may have marked off a mask in the mshr - //only write into the cache unmasked bytes. - //since this doesn't affect timing we don't actually do it. - repl_addr = shd_cache_fill(sc->L1cache,mf->addr,sc->gpu_cycle); - } + m_mshr_unit->mshr_return_from_mem(mf->mshr); + if (mf->mshr->istexture()) + shd_cache_fill(m_L1T,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle); + else if (mf->mshr->isconst()) + shd_cache_fill(m_L1C,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle); + else if (!m_config->gpgpu_no_dl1) + shd_cache_fill(m_L1D,mf->addr,gpu_sim_cycle+gpu_tot_sim_cycle); } - freed_read_mfs++; - free(mf); + delete mf; } -unsigned char fq_pop(int tpc_id) +void shader_core_ctx::store_ack( class mem_fetch *mf ) { - mem_fetch_t *mf; - - mf = (mem_fetch_t*) icnt_pop(tpc_id); - - // if there is a memory fetch request coming back, forward it to the proper shader core - if (mf) { - assert(mf->type == REPLY_DATA); - time_vector_update(mf->mshr->insts[0].uid ,MR_2SH_FQ_POP,gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ) ; - fill_shd_L1_with_new_line(sc[mf->sid], mf); + if (!strcmp("GT200",m_config->pipeline_model) ) { + unsigned warp_id = mf->wid; + m_warp[warp_id].dec_store_req(); } - return 0; } -//////////////////////////////////////////////////////////////////////////////////////////////// - -int issue_block2core( shader_core_ctx_t *shdr, int grid_num ) +void gpgpu_sim::fq_pop(int tpc_id) { - int tid, nthreads_2beissued, more_threads; - int nthreads_in_block= 0; - int start_thread = 0; - int end_thread = shdr->n_threads; - int cta_id=-1; - int cta_size=0; - int padded_cta_size; + mem_fetch *mf = (mem_fetch*) icnt_pop(tpc_id); + if (!mf) + return; + assert(mf->type == REPLY_DATA); + if( mf->mshr && mf->mshr->has_inst() ) + time_vector_update(mf->mshr->get_insts_uid() ,MR_2SH_FQ_POP,gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ); + if (mf->m_write) { + m_sc[mf->sid]->store_ack(mf); + delete mf; + } else { + m_memory_stats->memlatstat_read_done(mf,m_shader_config->max_warps_per_shader); + m_sc[mf->sid]->fill_shd_L1_with_new_line(mf); + } +} - cta_size = ptx_sim_cta_size(); - padded_cta_size = cta_size; +//////////////////////////////////////////////////////////////////////////////////////////////// - assert(gpgpu_spread_blocks_across_cores); //should be if muliple CTA per shader supported +/** + * Launches a cooperative thread array (CTA). + * + * @param kernel + * object that tells us which kernel to ask for a CTA from + */ - for (unsigned i=0;i<max_cta_per_shader(shdr);i++ ) { //try to find next empty cta slot - if (shdr->cta_status[i]==0) { // - cta_id=i; +void shader_core_ctx::issue_block2core( kernel_info_t &kernel ) +{ + // find a free CTA context + unsigned free_cta_hw_id=(unsigned)-1; + unsigned max_concurrent_cta_this_kernel = max_cta(kernel.entry()); + assert( max_concurrent_cta_this_kernel <= MAX_CTA_PER_SHADER ); + for (unsigned i=0;i<max_concurrent_cta_this_kernel;i++ ) { + if( m_cta_status[i]==0 ) { + free_cta_hw_id=i; break; } - } - assert( cta_id!=-1);//must have found a CTA to run - if (padded_cta_size%warp_size) { - padded_cta_size = ((padded_cta_size/warp_size)+1)*(warp_size); - } - start_thread = cta_id * padded_cta_size; - end_thread = start_thread + cta_size; - shader_reinit(shdr,start_thread, end_thread); - - // issue threads in blocks (if it is specified) - warp_set_t warps; - for (int i = start_thread; i<end_thread; i++) { //setup the block - unsigned warp_id = i/warp_size; - shdr->thread[i].cta_id = cta_id; - nthreads_in_block += ptx_sim_init_thread(&shdr->thread[i].ptx_thd_info,shdr->sid,i,cta_size-(i-start_thread),shdr->n_threads/*cta_size*/,shdr,cta_id,warp_id); - warps.set( warp_id ); - } - shdr->allocate_barrier( cta_id, warps ); + } + assert( free_cta_hw_id!=(unsigned)-1 ); - shader_init_CTA(shdr, start_thread, end_thread); - nthreads_2beissued = nthreads_in_block; - shdr->cta_status[cta_id]+=nthreads_2beissued; - assert( nthreads_2beissued ); //we should have not reached this point if there is no more thread to - + // determine hardware threads and warps that will be used for this CTA + int cta_size = kernel.threads_per_cta(); - assert( (unsigned) nthreads_2beissued <= shdr->n_threads); //confirm threads to be issued is less than or equal to number of threads supported by microarchitecture + // hw warp id = hw thread id mod warp size, so we need to find a range + // of hardware thread ids corresponding to an integral number of hardware + // thread ids + int padded_cta_size = cta_size; + if (cta_size%m_config->warp_size) + padded_cta_size = ((cta_size/m_config->warp_size)+1)*(m_config->warp_size); + unsigned start_thread = free_cta_hw_id * padded_cta_size; + unsigned end_thread = start_thread + cta_size; - int n_cta_issued= nthreads_2beissued/cta_size ;//+ nthreads_2beissued%cta_size; - shdr->n_active_cta += n_cta_issued; - shader_CTA_count_log(shdr->sid, n_cta_issued); - g_total_cta_left-= n_cta_issued; + // reset the microarchitecture state of the selected hardware thread and warp contexts + reinit(start_thread, end_thread,false); + + // initalize scalar threads and determine which hardware warps they are allocated to + // bind functional simulation state of threads to hardware resources (simulation) + warp_set_t warps; + unsigned nthreads_in_block= 0; + for (unsigned i = start_thread; i<end_thread; i++) { + m_thread[i].m_cta_id = free_cta_hw_id; + unsigned warp_id = i/m_config->warp_size; + nthreads_in_block += ptx_sim_init_thread(kernel,&m_thread[i].m_functional_model_thread_state,m_sid,i,cta_size-(i-start_thread),m_config->n_thread_per_shader,this,free_cta_hw_id,warp_id); + warps.set( warp_id ); + } + assert( nthreads_in_block > 0 && nthreads_in_block <= m_config->n_thread_per_shader); // should be at least one, but less than max + m_cta_status[free_cta_hw_id]=nthreads_in_block; - more_threads = 1; - if (gpgpu_spread_blocks_across_cores) { - nthreads_2beissued += start_thread; - } - printf("GPGPU-Sim uArch: Shader %d initializing CTA #%d with hw tids from %d to %d @(%lld,%lld)", - shdr->sid, cta_id, start_thread, nthreads_2beissued, gpu_sim_cycle, gpu_tot_sim_cycle ); - printf(" shdr->not_completed = %d\n", shdr->not_completed); - - for (tid=start_thread;tid<nthreads_2beissued;tid++) { + // now that we know which warps are used in this CTA, we can allocate + // resources for use in CTA-wide barrier operations + allocate_barrier( free_cta_hw_id, warps ); - // reset complete flag for stream - shdr->not_completed += 1; - assert( shdr->warp[tid/warp_size].n_completed > 0 ); - assert( shdr->warp[tid/warp_size].n_completed <= warp_size); - shdr->warp[tid/warp_size].n_completed--; + // initialize the SIMT stacks and fetch hardware + init_warps(start_thread, end_thread); - // set avail4fetch flag to ready - shdr->thread[tid].avail4fetch = 1; - assert( shdr->warp[tid/warp_size].n_avail4fetch < warp_size ); - shdr->warp[tid/warp_size].n_avail4fetch++; - - g_nthreads_issued++; - } + m_n_active_cta++; + g_total_cta_left-=1; // used for exiting early from simulation - if (!nthreads_in_block) more_threads = 0; - return more_threads; //if there are no more threads to be issued, return 0 + shader_CTA_count_log(m_sid, 1); + + printf("GPGPU-Sim uArch: Shader %d initialized CTA #%d with hw tids from %d to %d @(%lld,%lld)", + m_sid, free_cta_hw_id, start_thread, start_thread+nthreads_in_block, gpu_sim_cycle, gpu_tot_sim_cycle ); + printf(" active threads = %d\n", get_not_completed() ); + } + /////////////////////////////////////////////////////////////////////////////////////////// // wrapper code to to create an illusion of a memory controller with L2 cache. -// -int mem_ctrl_full( int mc_id ) -{ - if (gpgpu_cache_dl2_opt) { - return L2c_full( dram[mc_id] ); - } else { - return( gpgpu_dram_sched_queue_size && dram_full(dram[mc_id]) ); - } -} //#define DEBUG_PARTIAL_WRITES -void mem_ctrl_push( int mc_id, mem_fetch_t* mf ) +void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle ) { - dram[mc_id]->m_request_tracker.insert(mf); - if (gpgpu_cache_dl2_opt) { - L2c_push(dram[mc_id], mf); - } else { - addrdec_t tlx; - addrdec_tlx(mf->addr, &tlx); -#if 0 //old chunking no longer valid. - if (gpgpu_partial_write_mask && mf->write) { - assert( gpgpu_no_dl1 ); // gpgpu_partial_write_mask is not supported with caches for now - } -#endif //#if 0 //old chunking no longer valid - dram_push(dram[mc_id], - tlx.bk, tlx.row, tlx.col, - mf->nbytes_L1, mf->write, - mf->wid, mf->sid, mf->cache_hits_waiting, mf->addr, mf); - memlatstat_dram_access(mf, mc_id, tlx.bk); - if (mf->mshr) mshr_update_status(mf->mshr,IN_DRAM_REQ_QUEUE); - } + if (req) { + rop_delay_t r; + r.req = req; + r.ready_cycle = cycle + 115; // Add 115*4=460 delay cycles + m_rop.push(r); + } + if ( !m_rop.empty() && (cycle >= m_rop.front().ready_cycle) ) { + mem_fetch* mf = m_rop.front().req; + m_rop.pop(); + if (mf->type==RD_REQ) { + if ( mf->mshr && mf->mshr->has_inst() ) + time_vector_update(mf->mshr->get_insts_uid(),MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ; + } else { + if ( mf->mshr && !mf->mshr->isinst() ) + time_vector_update(mf->request_uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ; + } + m_stats->memlatstat_icnt2mem_pop(mf); + request_tracker_insert(mf); + if (m_config->gpgpu_cache_dl2_opt) { + if (m_config->gpgpu_l2_readoverwrite && mf->m_write) + cbtoL2writequeue->push(mf,gpu_sim_cycle); + else + cbtoL2queue->push(mf,gpu_sim_cycle); + m_accessLocality->access(mf); + if (mf->mshr) mf->mshr->set_status(IN_CBTOL2QUEUE); + } else { + m_dram->push(mf); + if (mf->mshr) mf->mshr->set_status(IN_DRAM_REQ_QUEUE); + } + } } -void* mem_ctrl_pop( int mc_id ) +mem_fetch* memory_partition_unit::pop() { - mem_fetch_t* mf; - if (gpgpu_cache_dl2_opt) { - mf = L2c_pop(dram[mc_id]); - if (mf && mf->mshr && mf->mshr->insts[0].callback.function) { - dram_callback_t* cb = &(mf->mshr->insts[0].callback); - cb->function(cb->instruction, cb->thread); + mem_fetch* mf; + if (m_config->gpgpu_cache_dl2_opt) { + mf = L2c_pop(m_dram); + if (mf && mf->mshr && mf->mshr->isatomic() ) { + dram_callback_t &cb = mf->mshr->get_atomic_callback(); + cb.function(cb.instruction, cb.thread); } - dram[mc_id]->m_request_tracker.erase(mf); - return mf; } else { - mf = static_cast<mem_fetch_t*> (dq_pop(dram[mc_id]->returnq)); //dram_pop(dram[mc_id]); + mf = m_dram->returnq_pop(gpu_sim_cycle); if (mf) mf->type = REPLY_DATA; - if (mf && mf->mshr && mf->mshr->insts[0].callback.function) { - dram_callback_t* cb = &(mf->mshr->insts[0].callback); - cb->function(cb->instruction, cb->thread); + if (mf && mf->mshr && mf->mshr->isatomic() ) { + dram_callback_t &cb = mf->mshr->get_atomic_callback(); + cb.function(cb.instruction, cb.thread); } - dram[mc_id]->m_request_tracker.erase(mf); - return mf; } + request_tracker_erase(mf); + return mf; } -void* mem_ctrl_top( int mc_id ) +mem_fetch* memory_partition_unit::top() { - mem_fetch_t* mf; - if (gpgpu_cache_dl2_opt) { - return L2c_top(dram[mc_id]); + if (m_config->gpgpu_cache_dl2_opt) { + return L2tocbqueue->top(); } else { - mf = static_cast<mem_fetch_t*> (dq_top(dram[mc_id]->returnq));//dram_top(dram[mc_id]); + mem_fetch* mf = m_dram->returnq_top(); if (mf) mf->type = REPLY_DATA; - return mf ;//dram_top(dram[mc_id]); + return mf; } } -void get_dram_output ( dram_t* dram_p ) -{ - mem_fetch_t* mf; - mem_fetch_t* mf_top; - mf_top = (mem_fetch_t*) dram_top(dram_p); //test +void memory_partition_unit::issueCMD() +{ + mem_fetch* mf_top = m_dram->top(); if (mf_top) { if (mf_top->type == DUMMY_READ) { - dram_pop(dram_p); + m_dram->pop(); free(mf_top); freed_dummy_read_mfs++; return; } } - if (gpgpu_cache_dl2_opt) { - L2c_get_dram_output( dram_p ); + if (m_config->gpgpu_cache_dl2_opt) { + L2c_get_dram_output(); } else { - if ( dq_full(dram_p->returnq) ) return; - mf = (mem_fetch_t*) dram_pop(dram_p); + if ( m_dram->returnq_full() ) + return; + mem_fetch* mf = m_dram->pop(); assert (mf_top==mf ); if (mf) { - dq_push(dram_p->returnq, mf); - if (mf->mshr) mshr_update_status(mf->mshr,IN_DRAMRETURN_Q); + m_dram->returnq_push(mf,gpu_sim_cycle); + if (mf->mshr) mf->mshr->set_status(IN_DRAMRETURN_Q); } } + m_dram->issueCMD(); + m_dram->dram_log(SAMPLELOG); } -void dram_log (int task ) { - static void ** mrqq_Dist; //memory request queue inside DRAM - if (task == CREATELOG) { - mrqq_Dist = (void **) calloc(gpu_n_mem,sizeof(void*)); - for (unsigned i=0;i<gpu_n_mem;i++) { - if (dram[i]->queue_limit) - mrqq_Dist[i] = StatCreate("mrqq_length",1,dram[i]->queue_limit); - else //queue length is unlimited; - mrqq_Dist[i] = StatCreate("mrqq_length",1,64); //track up to 64 entries - } - } else if (task == SAMPLELOG) { - for (unsigned i=0;i<gpu_n_mem;i++) { - StatAddSample(mrqq_Dist[i], dram_que_length(dram[i])); - } - } else if (task == DUMPLOG) { - for (unsigned i=0;i<gpu_n_mem;i++) { - printf ("Queue Length DRAM[%d] ",i);StatDisp(mrqq_Dist[i]); - } - } -} - -void dramqueue_latency_log_dump() +void dram_t::dram_log( int task ) { - for (unsigned i=0;i<gpu_n_mem;i++) { - printf ("(LOGB2)Latency DRAM[%d] ",i);StatDisp(dram[i]->mrqq->lat_stat); - printf ("(LOGB2)Latency DRAM[%d] ",i);StatDisp(dram[i]->rwq->lat_stat); + if (task == SAMPLELOG) { + StatAddSample(mrqq_Dist, que_length()); + } else if (task == DUMPLOG) { + printf ("Queue Length DRAM[%d] ",id);StatDisp(mrqq_Dist); } } //Find next clock domain and increment its time -inline int next_clock_domain(void) +int gpgpu_sim::next_clock_domain(void) { double smallest = min3(core_time,icnt_time,dram_time); int mask = 0x00; - if (gpgpu_cache_dl2_opt //when no-L2 it will never be L2's turn + if (m_memory_config->gpgpu_cache_dl2_opt //when no-L2 it will never be L2's turn && ( l2_time <= smallest) ) { smallest = l2_time; mask |= L2 ; @@ -1411,181 +1318,114 @@ inline int next_clock_domain(void) return mask; } -void gpu_sim_loop( int grid_num ) +unsigned long long g_single_step=0; // set this in gdb to single step the pipeline + +void gpgpu_sim::gpu_sim_loop() { int clock_mask = next_clock_domain(); // shader core loading (pop from ICNT into shader core) follows CORE clock if (clock_mask & CORE ) { - for (int i=0;i<gpu_n_tpc;i++) { + for (int i=0;i<gpu_n_tpc;i++) fq_pop(i); - } } - if (clock_mask & ICNT) { - // pop from memory controller to interconnect - static unsigned int *rt_size = NULL; - if (!rt_size) rt_size = (unsigned int*) malloc ((gpu_n_tpc+gpu_n_mem)*sizeof(unsigned int)); - memset(rt_size, 0, (gpu_n_tpc+gpu_n_mem)*sizeof(unsigned int)); - - for (unsigned i=0;i<gpu_n_mem;i++) { - - mem_fetch_t* mf; - - mf = (mem_fetch_t*) mem_ctrl_top(i); //(returns L2_top or DRAM returnq top) - - if (mf) { - mf->source_node = mem2device(i); - assert( mf->type != RD_REQ && mf->type != WT_REQ ); // never should a request come out from L2 or dram - if (!mf->write) { - int return_dev = -1; - return_dev = mf->sid / gpu_concentration; - assert(return_dev != -1); - // check icnt resource for READ data return - rt_size[return_dev] = mf->nbytes_L1; - if ( icnt_has_buffer( mem2device(i), rt_size) ) { - if (mf->mshr) mshr_update_status(mf->mshr,IN_ICNT2SHADER); - memlatstat_icnt2sh_push(mf); - time_vector_update(mf->mshr->insts[0].uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ); - icnt_push( mem2device(i), return_dev, mf, mf->nbytes_L1); - mem_ctrl_pop(i); - } else { - gpu_stall_icnt2sh++; - } - rt_size[return_dev] = 0; // clean up for the next dram_pop - } else { - time_vector_update(mf->request_uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,WT_REQ ) ; - mem_ctrl_pop(i); - free(mf); - freed_L1write_mfs++; - gpgpu_n_processed_writes++; + if (clock_mask & ICNT) { + // pop from memory controller to interconnect + for (unsigned i=0;i<m_n_mem;i++) { + mem_fetch* mf = m_memory_partition_unit[i]->top(); + if (mf) { + assert( mf->type != RD_REQ && mf->type != WT_REQ ); + unsigned response_size = mf->m_write?mf->nbytes_L1:WRITE_PACKET_SIZE; + if ( icnt_has_buffer( mem2device(i), response_size ) ) { + if (!mf->m_write) { + if (mf->mshr) mf->mshr->set_status(IN_ICNT2SHADER); + m_memory_stats->memlatstat_icnt2sh_push(mf); + if ( mf->mshr && mf->mshr->has_inst() ) + time_vector_update(mf->mshr->get_insts_uid(),MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ); + } else { + time_vector_update(mf->request_uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,WT_REQ ) ; + freed_L1write_mfs++; + gpgpu_n_processed_writes++; + } + int return_dev = mf->sid / gpu_concentration; + icnt_push( mem2device(i), return_dev, mf, response_size ); + m_memory_partition_unit[i]->pop(); + } else { + gpu_stall_icnt2sh++; + } } - } - } - } + } + } if (clock_mask & DRAM) { - for (unsigned i=0;i<gpu_n_mem;i++) { - get_dram_output ( dram[i] ); - } - // Issue the dram command (scheduler + delay model) - for (unsigned i=0;i<gpu_n_mem;i++) { - dram_issueCMD(dram[i]); + for (unsigned i=0;i<m_n_mem;i++) { + m_memory_partition_unit[i]->issueCMD(); // Issue the dram command (scheduler + delay model) } - dram_log(SAMPLELOG); } // L2 operations follow L2 clock domain if (clock_mask & L2) { - for (unsigned i=0;i<gpu_n_mem;i++) { - L2c_process_dram_output ( dram[i], i ); // pop from dram - L2c_push_miss_to_dram ( dram[i] ); //push to dram - L2c_service_mem_req ( dram[i], i ); // pop(push) from(to) icnt2l2(l2toicnt) queues; service l2 requests - } - if (gpgpu_cache_dl2_opt) { // L2 cache enabled - for (unsigned i=0;i<gpu_n_mem;i++) { - L2c_update_stat( dram[i] ); - } - } - if (gpgpu_cache_dl2_opt) { //take a sample of l2c queue lengths - L2c_log(SAMPLELOG); - } + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->cache_cycle(); } if (clock_mask & ICNT) { - // pop memory request from ICNT and - // push it to a dram delay queue - for (unsigned i=0;i<gpu_n_mem;i++) { - // Push memory request to dram delay queue if mem_ctrl is not full - if ( mem_ctrl_full(i) ) { + for (unsigned i=0;i<m_n_mem;i++) { + if ( m_memory_partition_unit[i]->full() ) { + gpu_stall_dramfull++; continue; } - - mem_fetch_t* mf; - mf = (mem_fetch_t*) icnt_pop( mem2device(i) ); - - if (mf) { - - dram_delay_t dram_delay; - dram_delay.mf = mf; - dram_delay.ready_cycle = gpu_sim_cycle + gpu_tot_sim_cycle + 115; // Add 115*4=460 delay cycles - dram_delay_queues[i].push(dram_delay); - } - } - - // pop memory request from dram delay queue and - // push it to the proper memory controller (L2 or DRAM controller) - for (unsigned i=0;i<gpu_n_mem;i++) { - if(!dram_delay_queues[i].empty() && dram_delay_queues[i].front().ready_cycle <= gpu_sim_cycle + gpu_tot_sim_cycle) { - if ( mem_ctrl_full(i) ) { - gpu_stall_dramfull++; - continue; - } - mem_fetch_t* mf = dram_delay_queues[i].front().mf; - if (mf->type==RD_REQ) { - time_vector_update(mf->mshr->insts[0].uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ; - } else { - time_vector_update(mf->request_uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ; - } - memlatstat_icnt2mem_pop(mf); - mem_ctrl_push( i, mf ); - - dram_delay_queues[i].pop(); - } + // move memory request from interconnect into memory partition (if memory controller not backed up) + mem_fetch* mf = (mem_fetch*) icnt_pop( mem2device(i) ); + m_memory_partition_unit[i]->push( mf, gpu_sim_cycle + gpu_tot_sim_cycle ); } - - icnt_transfer( ); + icnt_transfer(); } if (clock_mask & CORE) { // L1 cache + shader core pipeline stages - for (unsigned i=0;i<gpu_n_shader;i++) { - if (sc[i]->not_completed || more_thread) - shader_cycle(sc[i], i, grid_num); - sc[i]->gpu_cycle++; + for (unsigned i=0;i<m_n_shader;i++) { + if (m_sc[i]->get_not_completed() || more_thread) { + if (!strcmp("GPGPUSIM_ORIG",m_shader_config->pipeline_model) ) + m_sc[i]->cycle(); + else if (!strcmp("GT200",m_shader_config->pipeline_model) ) + m_sc[i]->cycle_gt200(); + } + } + if( g_single_step && ((gpu_sim_cycle+gpu_tot_sim_cycle) >= g_single_step) ) { + asm("int $03"); } gpu_sim_cycle++; if( g_interactive_debugger_enabled ) gpgpu_debug(); - for (unsigned i=0;i<gpu_n_shader && more_thread;i++) { - if (gpgpu_spread_blocks_across_cores) { - int cta_issue_count = 1; - if ( ( (unsigned) (sc[i]->n_active_cta + cta_issue_count) <= max_cta_per_shader(sc[i]) ) - && g_total_cta_left ) { - int j; - for (j=0;j<cta_issue_count;j++) { - issue_block2core(sc[i], grid_num); - } - if (!g_total_cta_left) { - more_thread = 0; - } - assert( g_total_cta_left > -1 ); - } - } else { - if (!(sc[i]->not_completed)) - more_thread = issue_block2core(sc[i], grid_num); + for (unsigned i=0;i<m_n_shader && more_thread;i++) { + if ( ( (m_sc[i]->get_n_active_cta()+1) <= m_sc[i]->max_cta(m_the_kernel.entry()) ) && g_total_cta_left ) { + m_sc[i]->issue_block2core( m_the_kernel ); + if (!g_total_cta_left) + more_thread = 0; + assert( g_total_cta_left > -1 ); } } - // Flush the caches once all of threads are completed. if (gpgpu_flush_cache) { int all_threads_complete = 1 ; - for (unsigned i=0;i<gpu_n_shader;i++) { - if (sc[i]->not_completed == 0) { - shader_cache_flush(sc[i]); + for (unsigned i=0;i<m_n_shader;i++) { + if (m_sc[i]->get_not_completed() == 0) { + m_sc[i]->cache_flush(); } else { all_threads_complete = 0 ; } } if (all_threads_complete) { printf("Flushed L1 caches...\n"); - if (gpgpu_cache_dl2_opt) { + if (m_memory_config->gpgpu_cache_dl2_opt) { int dlc = 0; - for (unsigned i=0;i<gpu_n_mem;i++) { - dlc = L2c_cache_flush(dram[i]); - printf("Dirty lines flushed from L2 %d is %d \n", i, dlc ); + for (unsigned i=0;i<m_n_mem;i++) { + dlc = m_memory_partition_unit[i]->L2c_cache_flush(); + printf("Dirty lines flushed from L2 %d is %d\n", i, dlc ); } } } @@ -1607,23 +1447,22 @@ void gpu_sim_loop( int grid_num ) (unsigned)days,(unsigned)hrs,(unsigned)minutes,(unsigned)sec, ctime(&curr_time)); fflush(stdout); - memlatstat_lat_pw(); + m_memory_stats->memlatstat_lat_pw(m_n_shader,m_shader_config->n_thread_per_shader,m_shader_config->warp_size); visualizer_printstat(); if (gpgpu_runtime_stat && (gpu_runtime_stat_flag != 0) ) { if (gpu_runtime_stat_flag & GPU_RSTAT_BW_STAT) { - for (unsigned i=0;i<gpu_n_mem;i++) { - dram_print_stat(dram[i],stdout); - } - printf("maxmrqlatency = %d \n", max_mrq_latency); - printf("maxmflatency = %d \n", max_mf_latency); + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->print_stat(stdout); + printf("maxmrqlatency = %d \n", m_memory_stats->max_mrq_latency); + printf("maxmflatency = %d \n", m_memory_stats->max_mf_latency); } if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) { printf("DWF_MS: "); - for (unsigned i=0;i<gpu_n_shader;i++) { + for (unsigned i=0;i<m_n_shader;i++) { printf("%u ",acc_dyn_pcs[i]); } printf("\n"); - print_thread_pc( stdout ); + print_thread_pc( stdout, m_n_shader ); } if (gpu_runtime_stat_flag & GPU_RSTAT_SHD_INFO) { shader_print_runtime_stat( stdout ); @@ -1635,25 +1474,24 @@ void gpu_sim_loop( int grid_num ) shader_print_l1_miss_stat( stdout ); } if (gpu_runtime_stat_flag & GPU_RSTAT_PDOM ) { - if (pdom_sched_type) { - printf ("pdom_original_warps_count %d \n",n_pdom_sc_orig_stat ); - printf ("pdom_single_warps_count %d \n",n_pdom_sc_single_stat ); + if (m_pdom_sched_type) { + printf ("pdom_original_warps_count %d \n",m_shader_stats->n_pdom_sc_orig_stat ); + printf ("pdom_single_warps_count %d \n",m_shader_stats->n_pdom_sc_single_stat ); } } if (gpu_runtime_stat_flag & GPU_RSTAT_SCHED ) { printf("Average Num. Warps Issuable per Shader:\n"); - for (unsigned i=0;i<gpu_n_shader;i++) { - printf("%2.2f ", (float) num_warps_issuable_pershader[i]/ gpu_stat_sample_freq); - num_warps_issuable_pershader[i] = 0; + for (unsigned i=0;i<m_n_shader;i++) { + printf("%2.2f ", (float) m_shader_stats->num_warps_issuable_pershader[i]/ gpu_stat_sample_freq); + m_shader_stats->num_warps_issuable_pershader[i] = 0; } printf("\n"); } } } - for (unsigned i=0;i<gpu_n_mem;i++) { - acc_mrq_length[i] += dram_que_length(dram[i]); - } + for (unsigned i=0;i<m_n_mem;i++) + m_memory_stats->acc_mrq_length[i] += m_memory_partition_unit[i]->dram_que_length(); if (!(gpu_sim_cycle % 20000)) { // deadlock detection if (gpu_deadlock_detect && gpu_sim_insn == last_gpu_sim_insn) { @@ -1667,56 +1505,21 @@ void gpu_sim_loop( int grid_num ) } } -void dump_regs(unsigned sid, unsigned tid) +void shader_core_ctx::dump_istream_state( FILE *fout ) { - if ( sid >= gpu_n_shader ) { - printf("shader %u is out of range\n",sid); - return; - } - if ( tid >= gpu_n_thread_per_shader ) { - printf("thread %u is out of range\n",tid); - return; - } - - shader_core_ctx_t *s = sc[sid]; - - ptx_dump_regs( s->thread[tid].ptx_thd_info ); + fprintf(fout, "\n"); + for (unsigned w=0; w < m_config->max_warps_per_shader; w++ ) + m_warp[w].print(fout); } -void shader_dump_istream_state(shader_core_ctx_t *shader, FILE *fout ) -{ - fprintf( fout, "\n"); - for (unsigned t=0; t < gpu_n_thread_per_shader/warp_size; t++ ) { - int tid = t*warp_size; - if ( shader->warp[t].n_completed < warp_size ) { - fprintf( fout, " %u:%3u (w%02u) fetch state = c:%u a4f:%u bw:%u (completed: ", shader->sid, tid, t, - shader->warp[t].n_completed, - shader->warp[t].n_avail4fetch, - shader->warp[t].n_waiting_at_barrier ); - - for (unsigned i = tid; i < (t+1)*warp_size; i++ ) { - if ( ptx_thread_done(shader->thread[i].ptx_thd_info) ) { - fprintf(fout,"1"); - } else { - fprintf(fout,"0"); - } - if ( (((i+1)%4) == 0) && (i+1) < (t+1)*warp_size ) { - fprintf(fout,","); - } - } - fprintf(fout,")\n"); - } - } -} - -void dump_pipeline_impl( int mask, int s, int m ) +void gpgpu_sim::dump_pipeline( int mask, int s, int m ) const { /* You may want to use this function while running GPGPU-Sim in gdb. One way to do that is add the following to your .gdbinit file: define dp - call dump_pipeline_impl((0x40|0x4|0x1),$arg0,0) + call g_the_gpu.dump_pipeline_impl((0x40|0x4|0x1),$arg0,0) end Then, typing "dp 3" will show the contents of the pipeline for shader core 3. @@ -1724,25 +1527,26 @@ void dump_pipeline_impl( int mask, int s, int m ) printf("Dumping pipeline state...\n"); if(!mask) mask = 0xFFFFFFFF; - for (unsigned i=0;i<gpu_n_shader;i++) { + for (unsigned i=0;i<m_n_shader;i++) { if(s != -1) { i = s; } - if(mask&1) shader_display_pipeline(sc[i], stdout, 1, mask & 0x2E ); - if(mask&0x40) shader_dump_istream_state(sc[i], stdout); - if(mask&0x100) mshr_print(stdout, sc[i]); + if(mask&1) m_sc[i]->display_pipeline(stdout, 1, mask & 0x2E ); + if (!strcmp("GPGPUSIM_ORIG",m_shader_config->pipeline_model) ) + if(mask&0x40) m_sc[i]->dump_istream_state(stdout); + if(mask&0x100) m_sc[i]->mshr_print(stdout, mask); if(s != -1) { break; } } if(mask&0x10000) { - for (unsigned i=0;i<gpu_n_mem;i++) { + for (unsigned i=0;i<m_n_mem;i++) { if(m != -1) { i=m; } printf("DRAM / memory controller %u:\n", i); - if(mask&0x100000) dram_print_stat(dram[i],stdout); - if(mask&0x1000000) dram_visualize( dram[i] ); + if(mask&0x100000) m_memory_partition_unit[i]->print_stat(stdout); + if(mask&0x1000000) m_memory_partition_unit[i]->visualize(); if(m != -1) { break; } @@ -1751,8 +1555,7 @@ void dump_pipeline_impl( int mask, int s, int m ) fflush(stdout); } -void dump_pipeline() +void memory_partition_unit::visualizer_print( gzFile visualizer_file ) { - dump_pipeline_impl(0,-1,-1); + m_dram->visualizer_print(visualizer_file); } - diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index 45d65e3..5bb9875 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -69,6 +69,10 @@ #ifndef GPU_SIM_H #define GPU_SIM_H +#include "../abstract_hardware_model.h" +#include <list> +#include <stdio.h> + // constants for statistics printouts #define GPU_RSTAT_SHD_INFO 0x1 #define GPU_RSTAT_BW_STAT 0x2 @@ -88,88 +92,289 @@ // clock constants #define MhZ *1000000 -extern void init_gpu(); -extern void gpu_reg_options(class OptionParser * opp); -extern unsigned int run_gpu_sim(int grid_num); -extern unsigned int get_converge_point(unsigned int pc, void *thd); -extern void gpu_print_stat(); -extern int mem_ctrl_full( int mc_id ); -extern void dramqueue_latency_log_dump(); -extern void dump_pipeline_impl( int mask, int s, int m ); +#define CREATELOG 111 +#define SAMPLELOG 222 +#define DUMPLOG 333 + +void increment_x_then_y_then_z( dim3 &i, const dim3 &bound); + +class kernel_info_t { +public: + kernel_info_t() + { + m_valid=false; + m_kernel_entry=NULL; + } + kernel_info_t( dim3 gridDim, dim3 blockDim, class function_info *entry ) + { + m_valid=true; + m_kernel_entry=entry; + m_grid_dim=gridDim; + m_block_dim=blockDim; + m_next_cta.x=0; + m_next_cta.y=0; + m_next_cta.z=0; + m_next_tid=m_next_cta; + } + + class function_info *entry() { return m_kernel_entry; } + + size_t num_blocks() const + { + return m_grid_dim.x * m_grid_dim.y * m_grid_dim.z; + } + + size_t threads_per_cta() const + { + return m_block_dim.x * m_block_dim.y * m_block_dim.z; + } + + dim3 get_grid_dim() const { return m_grid_dim; } + dim3 get_cta_dim() const { return m_block_dim; } + + void increment_cta_id() + { + increment_x_then_y_then_z(m_next_cta,m_grid_dim); + m_next_tid.x=0; + m_next_tid.y=0; + m_next_tid.z=0; + } + dim3 get_next_cta_id() const { return m_next_cta; } + bool no_more_ctas_to_run() const + { + return (m_next_cta.x >= m_grid_dim.x || m_next_cta.y >= m_grid_dim.y || m_next_cta.z >= m_grid_dim.z ); + } + + void increment_thread_id() { increment_x_then_y_then_z(m_next_tid,m_block_dim); } + dim3 get_next_thread_id_3d() const { return m_next_tid; } + unsigned get_next_thread_id() const + { + return m_next_tid.x + m_block_dim.x*m_next_tid.y + m_block_dim.x*m_block_dim.y*m_next_tid.z; + } + bool more_threads_in_cta() const + { + return m_next_tid.z < m_block_dim.z && m_next_tid.y < m_block_dim.y && m_next_tid.z < m_block_dim.x; + } + +private: + bool m_valid; + class function_info *m_kernel_entry; + + dim3 m_grid_dim; + dim3 m_block_dim; + dim3 m_next_cta; + dim3 m_next_tid; +}; + +enum divergence_support_t { + POST_DOMINATOR = 1, + MIMD = 2, + DWF = 3, + NUM_SIMD_MODEL +}; + +struct shader_core_config +{ + char *pipeline_model; + unsigned warp_size; + bool gpgpu_perfect_mem; + enum divergence_support_t model; + unsigned n_thread_per_shader; + unsigned max_warps_per_shader; + unsigned max_cta_per_core; //Limit on number of concurrent CTAs in shader core + unsigned pdom_sched_type; + bool gpgpu_no_dl1; + char *gpgpu_cache_texl1_opt; + char *gpgpu_cache_constl1_opt; + char *gpgpu_cache_dl1_opt; + char *gpgpu_cache_il1_opt; + unsigned n_mshr_per_shader; + bool gpgpu_dwf_reg_bankconflict; + bool gpgpu_operand_collector; + int gpgpu_operand_collector_num_units; + int gpgpu_operand_collector_num_units_sfu; + unsigned gpgpu_pre_mem_stages; + bool gpgpu_no_divg_load; + bool gpgpu_stall_on_use; + bool gpgpu_cache_wt_through; + //Shader core resources + unsigned gpgpu_shmem_size; + unsigned gpgpu_shader_registers; + int gpgpu_warpdistro_shader; + int gpgpu_interwarp_mshr_merge; + int gpgpu_n_shmem_bank; + int gpgpu_n_cache_bank; + int gpgpu_shmem_port_per_bank; + int gpgpu_cache_port_per_bank; + int gpgpu_const_port_per_bank; + int gpgpu_shmem_pipe_speedup; + unsigned gpgpu_num_reg_banks; + unsigned gpu_max_cta_per_shader; // TODO: modify this for fermi... computed based upon kernel + // resource usage; used in shader_core_ctx::translate_local_memaddr + bool gpgpu_reg_bank_use_warp_id; + int gpgpu_coalesce_arch; + bool gpgpu_local_mem_map; + int gpu_padded_cta_size; + unsigned gpgpu_dwf_rr_stage_n_reg_banks; + int m_using_dwf_rrstage; // model register read bank conflicts in DWF (i.e., not "lane aware") + int using_commit_queue; //is the scheduler using commit_queue? +}; + +enum dram_ctrl_t { + DRAM_FIFO=0, + DRAM_IDEAL_FAST=1 +}; + +struct memory_config { + char *gpgpu_cache_dl2_opt; + char *gpgpu_dram_timing_opt; + char *gpgpu_L2_queue_config; + bool gpgpu_l2_readoverwrite; + bool l2_ideal; + unsigned gpgpu_dram_sched_queue_size; + unsigned int gpu_mem_n_bk; + enum dram_ctrl_t scheduler_type; + bool gpgpu_memlatency_stat; + unsigned gpgpu_dram_buswidth; + unsigned gpgpu_dram_burst_length; +}; + +// global config +extern int gpgpu_mem_address_mask; +extern unsigned int gpu_n_mem_per_ctrlr; + +extern bool gpgpu_thread_swizzling; + +extern int gpu_runtime_stat_flag; +extern int gpgpu_cflog_interval; + +extern bool g_interactive_debugger_enabled; + +extern int g_ptx_inst_debug_to_file; +extern char* g_ptx_inst_debug_file; +extern int g_ptx_inst_debug_thread_uid; + + + + +class gpgpu_sim { +public: + gpgpu_sim(); + + void reg_options(class OptionParser * opp); + void init_gpu(); + void set_prop( struct cudaDeviceProp *prop ); + + void launch( kernel_info_t &kinfo ); + void next_grid( unsigned &grid_num, class function_info *&entry ); + + unsigned run_gpu_sim(); + + unsigned get_L2_linesize() const; + + unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid ); + void decrement_atomic_count( unsigned sid, unsigned wid ); + void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc ); + const kernel_info_t &the_kernel() const { return m_the_kernel; } + + int shared_mem_size() const; + int num_registers_per_core() const; + int wrp_size() const; + int shader_clock() const; + const struct cudaDeviceProp *get_prop() const; + enum divergence_support_t simd_model() const; + + unsigned num_shader() const { return m_n_shader; } + unsigned threads_per_core() const; + void mem_instruction_stats( class inst_t* warp); + int issue_mf_from_fq(class mem_fetch *mf); + + void gpu_print_stat() const; + void dump_pipeline( int mask, int s, int m ) const; + +private: + // clocks + void init_clock_domains(void); + void reinit_clock_domains(void); + int next_clock_domain(void); + + unsigned char check_icnt_has_buffer(unsigned long long int addr, int bsize, int sid ); + void gpu_sim_loop(); + void fq_pop(int tpc_id); + void L2c_options(class OptionParser *opp); + void L2c_print_cache_stat() const; + void L2c_print_debug(); + void L2c_latency_log_dump(); + void shader_print_runtime_stat( FILE *fout ); + void shader_print_l1_miss_stat( FILE *fout ); + void shader_print_accstats( FILE* fout ) const; + void visualizer_printstat(); + void print_shader_cycle_distro( FILE *fout ) const; + + void gpgpu_debug(); + + // data + class shader_core_ctx **m_sc; + class memory_partition_unit **m_memory_partition_unit; + + unsigned m_grid_num; + kernel_info_t m_the_kernel; + std::list<kernel_info_t> m_running_kernels; + + // clock domains - frequency + double core_freq; + double icnt_freq; + double dram_freq; + double l2_freq; + + // clock period + double core_period; + double icnt_period; + double dram_period; + double l2_period; + + // time of next rising edge + double core_time; + double icnt_time; + double dram_time; + double l2_time; + + // configuration parameters + bool m_options_set; + struct cudaDeviceProp *m_cuda_properties; + struct shader_core_config *m_shader_config; + struct memory_config *m_memory_config; + unsigned int m_n_shader; + unsigned int m_n_mem; + int gpu_concentration; + + int m_pdom_sched_type; + + struct shader_core_stats *m_shader_stats; + class memory_stats_t *m_memory_stats; +public: + unsigned long long gpu_sim_insn_last_update; +}; + +// global counters -extern unsigned int L1_write_miss; -extern unsigned int L1_read_miss; -extern unsigned int L1_texture_miss; -extern unsigned int L1_const_miss; -extern unsigned int L1_write_hit_on_miss; -extern unsigned int L1_writeback; -extern unsigned int L1_const_miss; -extern bool gpgpu_perfect_mem; -extern bool gpgpu_no_dl1; -extern char *gpgpu_cache_texl1_opt; -extern char *gpgpu_cache_constl1_opt; -extern char *gpgpu_cache_dl1_opt; -extern unsigned int gpu_n_thread_per_shader; -extern unsigned int gpu_n_mshr_per_shader; -extern unsigned int gpu_n_shader; -extern unsigned int gpu_n_mem; -extern bool gpgpu_reg_bankconflict; -extern int gpgpu_dram_sched_queue_size; extern unsigned long long gpu_sim_cycle; extern unsigned long long gpu_tot_sim_cycle; extern unsigned long long gpu_sim_insn; -extern unsigned int gpu_n_warp_per_shader; +extern unsigned long long gpu_tot_sim_insn; +extern unsigned g_next_mf_request_uid; + +// stats + extern unsigned int **max_conc_access2samerow; extern unsigned int **max_servicetime2samerow; extern unsigned int **row_access; extern unsigned int **num_activates; -extern struct dram_timing **dram; -extern int *num_warps_issuable; -extern int *num_warps_issuable_pershader; -extern unsigned long long gpu_sim_insn_no_ld_const; -extern unsigned long long gpu_sim_insn_last_update; -extern unsigned long long gpu_completed_thread; -extern class shader_core_ctx **sc; -extern unsigned int gpgpu_pre_mem_stages; -extern bool gpgpu_no_divg_load; -extern bool gpgpu_thread_swizzling; -extern bool gpgpu_strict_simd_wrbk; -extern unsigned int warp_conflict_at_writeback; -extern unsigned int gpgpu_commit_pc_beyond_two; -extern bool gpgpu_spread_blocks_across_cores; -extern int gpgpu_cflog_interval; -extern unsigned int gpu_stall_by_MSHRwb; -extern unsigned int gpu_stall_shd_mem; -extern unsigned int gpu_stall_sh2icnt; -extern bool gpgpu_operand_collector; -extern int gpgpu_operand_collector_num_units; -extern int gpgpu_operand_collector_num_units_sfu; -extern int gpu_runtime_stat_flag; -extern unsigned int *max_return_queue_length; -extern int gpgpu_partial_write_mask; -extern int gpgpu_n_mem_write_local; -extern int gpgpu_n_mem_write_global; -extern bool gpgpu_cache_wt_through; -extern double core_freq; -extern double icnt_freq; -extern double dram_freq; -extern double l2_freq; -extern int pdom_sched_type; -extern int n_pdom_sc_orig_stat; -extern int n_pdom_sc_single_stat; -extern bool gpgpu_cuda_sim; -extern int gpgpu_mem_address_mask; -extern bool g_interactive_debugger_enabled; -extern unsigned int gpu_n_mem_per_ctrlr; extern unsigned int **concurrent_row_access; //concurrent_row_access[dram chip id][bank id] -extern unsigned long long gpu_tot_sim_insn; + extern unsigned int gpgpu_n_sent_writes; extern unsigned int gpgpu_n_processed_writes; -extern int gpgpu_simd_model; -extern unsigned int gpu_mem_n_bk; -extern unsigned g_next_mf_request_uid; -extern int g_ptx_inst_debug_to_file; -extern char* g_ptx_inst_debug_file; -extern int g_ptx_inst_debug_thread_uid; +extern unsigned made_write_mfs; +extern unsigned made_read_mfs; #endif diff --git a/src/gpgpu-sim/icnt_wrapper.cc b/src/gpgpu-sim/icnt_wrapper.cc index aa55110..25238f9 100644 --- a/src/gpgpu-sim/icnt_wrapper.cc +++ b/src/gpgpu-sim/icnt_wrapper.cc @@ -85,12 +85,12 @@ void icnt_reg_options( class OptionParser * opp ) option_parser_register(opp, "-inter_config_file", OPT_CSTR, &g_network_config_filename, "Interconnection network config file", "mesh"); } -void icnt_init( unsigned int n_shader, unsigned int n_mem ) +void icnt_init( unsigned int n_shader, unsigned int n_mem, struct shader_core_config *shader_config ) { switch (g_network_mode) { case INTERSIM: - init_interconnect(g_network_config_filename ,n_shader, n_mem); + init_interconnect(g_network_config_filename, n_shader, n_mem, shader_config ); icnt_has_buffer = interconnect_has_buffer; icnt_push = interconnect_push; icnt_pop = interconnect_pop; diff --git a/src/gpgpu-sim/icnt_wrapper.h b/src/gpgpu-sim/icnt_wrapper.h index 0961fc4..26e394b 100644 --- a/src/gpgpu-sim/icnt_wrapper.h +++ b/src/gpgpu-sim/icnt_wrapper.h @@ -68,7 +68,7 @@ #define ICNT_WRAPPER_H // functional interface to the interconnect -typedef int (*icnt_has_buffer_p)(unsigned int input, unsigned int *size); +typedef int (*icnt_has_buffer_p)(unsigned int input, unsigned int size); typedef void (*icnt_push_p)(unsigned int input, unsigned int output, void* data, unsigned int size); typedef void* (*icnt_pop_p)(unsigned int output); typedef void (*icnt_transfer_p)( ); @@ -88,7 +88,7 @@ enum network_mode { N_NETWORK_MODE }; -void icnt_init( unsigned int n_shader, unsigned int n_mem ); +void icnt_init( unsigned int n_shader, unsigned int n_mem, struct shader_core_config *shader_config ); void icnt_reg_options( class OptionParser * opp ); #endif diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc index f27c940..cbed2e9 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -1,10 +1,75 @@ +/* + * l2cache.cc + * + * Copyright (c) 2009 by Tor M. Aamodt and + * University of British Columbia + * Vancouver, BC V6T 1Z4 + * All Rights Reserved. + * + * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE + * TERMS AND CONDITIONS. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h + * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda + * (property of NVIDIA). The files benchmarks/BlackScholes/ and + * benchmarks/template/ are derived from the CUDA SDK available from + * http://www.nvidia.com/cuda (also property of NVIDIA). The files from + * src/intersim/ are derived from Booksim (a simulator provided with the + * textbook "Principles and Practices of Interconnection Networks" available + * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by + * the corresponding legal terms and conditions set forth separately (original + * copyright notices are left in files from these sources and where we have + * modified a file our copyright notice appears before the original copyright + * notice). + * + * Using this version of GPGPU-Sim requires a complete installation of CUDA + * which is distributed seperately by NVIDIA under separate terms and + * conditions. To use this version of GPGPU-Sim with OpenCL requires a + * recent version of NVIDIA's drivers which support OpenCL. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the University of British Columbia nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. + * + * 5. No nonprofit user may place any restrictions on the use of this software, + * including as modified by the user, by any other authorized user. + * + * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, + * Ali Bakhoda, George L. Yuan, at the University of British Columbia, + * Vancouver, BC V6T 1Z4 + */ + + #include <stdlib.h> #include <stdio.h> #include <string.h> #include <list> #include <set> -#include "../tr1_hash_map.h" // for unordered_map failback #include "../option_parser.h" #include "mem_fetch.h" @@ -15,137 +80,52 @@ #include "../intersim/statwraper.h" #include "../abstract_hardware_model.h" #include "gpu-sim.h" +#include "shader.h" +#include "mem_latency_stat.h" -class L2c_mshr; -class L2c_miss_tracker; -class L2c_access_locality; - -mem_fetch_t* g_debug_mf = NULL; - -// L2 cache block (include the cache model + flow controls) -struct L2cacheblk -{ - shd_cache_t *L2cache; - - delay_queue *cbtoL2queue; //latency 10 - delay_queue *cbtoL2writequeue; - delay_queue *dramtoL2queue; //latency 10 - delay_queue *dramtoL2writequeue; - delay_queue *L2todramqueue; //latency 0 - delay_queue *L2todram_wbqueue; - delay_queue *L2tocbqueue; //latency 0 - - mem_fetch_t *L2request; //request currently being serviced by the L2 Cache - - L2c_mshr *m_mshr; // mshr model - L2c_miss_tracker *m_missTracker; // tracker observing for redundant misses - L2c_access_locality *m_accessLocality; // tracking true locality of L2 Cache access - - L2cacheblk(size_t linesize); - ~L2cacheblk(); -}; +template class fifo_pipeline<mem_fetch>; // external dependencies extern unsigned long long int addrdec_mask[5]; -extern int gpgpu_dram_sched_queue_size; extern unsigned made_write_mfs; extern unsigned freed_L1write_mfs; extern unsigned freed_L2write_mfs; -void memlatstat_icnt2sh_push(mem_fetch_t *mf); -void memlatstat_dram_access(mem_fetch_t *mf, unsigned dram_id, unsigned bank); -void memlatstat_start(mem_fetch_t *mf); -unsigned memlatstat_done(mem_fetch_t *mf); +address_type L2c_mshr::cache_tag(const mem_fetch *mf) const +{ + return (mf->addr & ~(m_linesize - 1)); +} + +address_type L2c_miss_tracker::cache_tag(const mem_fetch *mf) const +{ + return (mf->addr & ~(m_linesize - 1)); +} -// option -char *gpgpu_L2_queue_config; -bool gpgpu_l2_readoverwrite; -bool l2_ideal; +address_type L2c_access_locality::cache_tag(const mem_fetch *mf) const +{ + return (mf->addr & ~(m_linesize - 1)); +} -void L2c_options(option_parser_t opp) +void gpgpu_sim::L2c_options(option_parser_t opp) { - option_parser_register(opp, "-gpgpu_L2_queue", OPT_CSTR, &gpgpu_L2_queue_config, + option_parser_register(opp, "-gpgpu_L2_queue", OPT_CSTR, &m_memory_config->gpgpu_L2_queue_config, "L2 data cache queue length and latency config", "0:0:0:0:0:0:10:10"); - option_parser_register(opp, "-gpgpu_l2_readoverwrite", OPT_BOOL, &gpgpu_l2_readoverwrite, + option_parser_register(opp, "-gpgpu_l2_readoverwrite", OPT_BOOL, &m_memory_config->gpgpu_l2_readoverwrite, "Prioritize read requests over write requests for L2", "0"); - option_parser_register(opp, "-l2_ideal", OPT_BOOL, &l2_ideal, + option_parser_register(opp, "-l2_ideal", OPT_BOOL, &m_memory_config->l2_ideal, "Use a ideal L2 cache that always hit", "0"); } -// stats -unsigned L2_write_miss = 0; -unsigned L2_write_hit = 0; -unsigned L2_read_hit = 0; -unsigned L2_read_miss = 0; -unsigned int *L2_cbtoL2length; -unsigned int *L2_cbtoL2writelength; -unsigned int *L2_L2tocblength; -unsigned int *L2_dramtoL2length; -unsigned int *L2_dramtoL2writelength; -unsigned int *L2_L2todramlength; //////////////////////////////////////////////// // L2 MSHR model -class L2c_mshr -{ -private: - typedef std::list<const mem_fetch_t*> mem_fetch_list; - typedef tr1_hash_map<address_type, mem_fetch_list> L2missGroup; - L2missGroup m_L2missgroup; // structure tracking redundant dram access - - struct active_chain { - address_type cacheTag; - mem_fetch_list *list; - active_chain() : cacheTag(0xDEADBEEF), list(NULL) { } - }; - active_chain m_active_mshr_chain; - size_t m_linesize; // L2 cache line size - - const size_t m_n_entries; // total number of entries available - size_t m_entries_used; // number of entries in use - - int m_n_miss; - int m_n_miss_serviced_by_dram; - int m_n_mshr_hits; - size_t m_max_entries_used; - - address_type cache_tag(const mem_fetch_t *mf) const - { - // return mf->addr; - return (mf->addr & ~(m_linesize - 1)); - } - -public: - L2c_mshr(size_t linesize, size_t n_entries = 64) - : m_linesize(linesize), m_n_entries(n_entries), m_entries_used(0), - m_n_miss(0), m_n_miss_serviced_by_dram(0), m_n_mshr_hits(0), m_max_entries_used(0) { } - - // add a cache miss to MSHR, return true if this access is hit another existing entry and merges with it - bool new_miss(const mem_fetch_t *mf); - - // notify MSHR that a new cache line has been fetched, activate the associated MSHR chain - void miss_serviced(const mem_fetch_t *mf); - - // probe if there are pending hits left in this MSHR chain - bool mshr_chain_empty(); - - // peek the first entry in the active MSHR chain - mem_fetch_t *mshr_chain_top(); - - // pop the first entry in the active MSHR chain - void mshr_chain_pop(); - - void print(FILE *fout = stdout); - void print_stat(FILE *fout = stdout); -}; - -bool L2c_mshr::new_miss(const mem_fetch_t *mf) +bool L2c_mshr::new_miss(const mem_fetch *mf) { address_type cacheTag = cache_tag(mf); mem_fetch_list &missGroup = m_L2missgroup[cacheTag]; @@ -163,7 +143,7 @@ bool L2c_mshr::new_miss(const mem_fetch_t *mf) return mshr_hit; } -void L2c_mshr::miss_serviced(const mem_fetch_t *mf) +void L2c_mshr::miss_serviced(const mem_fetch *mf) { assert(m_active_mshr_chain.list == NULL); address_type cacheTag = cache_tag(mf); @@ -185,12 +165,12 @@ bool L2c_mshr::mshr_chain_empty() return (m_active_mshr_chain.list == NULL); } -mem_fetch_t *L2c_mshr::mshr_chain_top() +mem_fetch *L2c_mshr::mshr_chain_top() { - const mem_fetch_t *mf = m_active_mshr_chain.list->back(); + const mem_fetch *mf = m_active_mshr_chain.list->back(); assert(cache_tag(mf) == m_active_mshr_chain.cacheTag); - return const_cast<mem_fetch_t*>(mf); + return const_cast<mem_fetch*>(mf); } void L2c_mshr::mshr_chain_pop() @@ -218,7 +198,7 @@ void L2c_mshr::print(FILE *fout) } } -void L2c_mshr::print_stat(FILE *fout) +void L2c_mshr::print_stat(FILE *fout) const { fprintf(fout, "L2c MSHR: max_entry = %zu, n_miss = %d, n_mshr_hits = %d, n_serviced_by_dram %d\n", m_max_entries_used, m_n_miss, m_n_mshr_hits, m_n_miss_serviced_by_dram); @@ -226,36 +206,8 @@ void L2c_mshr::print_stat(FILE *fout) //////////////////////////////////////////////// // track redundant dram access generated by L2 cache -class L2c_miss_tracker -{ -private: - typedef std::set<mem_fetch_t*> mem_fetch_set; - typedef tr1_hash_map<address_type, mem_fetch_set> L2missGroup; - L2missGroup m_L2missgroup; // structure tracking redundant dram access - size_t m_linesize; // L2 cache line size - - typedef tr1_hash_map<address_type, int> L2redundantCnt; - L2redundantCnt m_L2redundantCnt; - - int m_totalL2redundantAcc; - - address_type cache_tag(const mem_fetch_t *mf) const - { - // return mf->addr; - return (mf->addr & ~(m_linesize - 1)); - } -public: - L2c_miss_tracker(size_t linesize) : m_linesize(linesize), m_totalL2redundantAcc(0) { } - void new_miss(mem_fetch_t *mf); - void miss_serviced(mem_fetch_t *mf); - - void print(FILE *fout, bool brief = true); - void print_stat(FILE *fout, bool brief = true); - -}; - -void L2c_miss_tracker::new_miss(mem_fetch_t *mf) +void L2c_miss_tracker::new_miss(mem_fetch *mf) { address_type cacheTag = cache_tag(mf); mem_fetch_set &missGroup = m_L2missgroup[cacheTag]; @@ -268,7 +220,7 @@ void L2c_miss_tracker::new_miss(mem_fetch_t *mf) missGroup.insert(mf); } -void L2c_miss_tracker::miss_serviced(mem_fetch_t *mf) +void L2c_miss_tracker::miss_serviced(mem_fetch *mf) { address_type cacheTag = cache_tag(mf); L2missGroup::iterator iMissGroup = m_L2missgroup.find(cacheTag); @@ -295,12 +247,12 @@ void L2c_miss_tracker::print(FILE *fout, bool brief) } } -void L2c_miss_tracker::print_stat(FILE *fout, bool brief) +void L2c_miss_tracker::print_stat(FILE *fout, bool brief) const { fprintf(fout, "RedundantMiss = %d\n", m_totalL2redundantAcc); if (brief == true) return; fprintf(fout, " Detail:"); - for (L2redundantCnt::iterator iL2rc = m_L2redundantCnt.begin(); iL2rc != m_L2redundantCnt.end(); ++iL2rc) { + for (L2redundantCnt::const_iterator iL2rc = m_L2redundantCnt.begin(); iL2rc != m_L2redundantCnt.end(); ++iL2rc) { fprintf(fout, "%#08x:%d ", iL2rc->first, iL2rc->second); } fprintf(fout, "\n"); @@ -308,76 +260,90 @@ void L2c_miss_tracker::print_stat(FILE *fout, bool brief) //////////////////////////////////////////////// // track all locality of L2 cache access -class L2c_access_locality -{ -private: - size_t m_linesize; // L2 cache line size - - typedef tr1_hash_map<address_type, int> L2accCnt; - L2accCnt m_L2accCnt; - - int m_totalL2accAcc; - - address_type cache_tag(const mem_fetch_t *mf) const - { - // return mf->addr; - return (mf->addr & ~(m_linesize - 1)); - } - -public: - L2c_access_locality(size_t linesize) : m_linesize(linesize), m_totalL2accAcc(0) { } - void access(mem_fetch_t *mf); - - void print_stat(FILE *fout, bool brief = true); - -}; - -void L2c_access_locality::access(mem_fetch_t *mf) +void L2c_access_locality::access(mem_fetch *mf) { address_type cacheTag = cache_tag(mf); m_L2accCnt[cacheTag] += 1; m_totalL2accAcc += 1; } -void L2c_access_locality::print_stat(FILE *fout, bool brief) +void L2c_access_locality::print_stat(FILE *fout, bool brief) const { float access_locality = (float) m_totalL2accAcc / m_L2accCnt.size(); fprintf(fout, "Access Locality = %d / %zu (%f) \n", m_totalL2accAcc, m_L2accCnt.size(), access_locality); if (brief == true) return; fprintf(fout, " Detail:"); pow2_histogram locality_histo(" Hits"); - for (L2accCnt::iterator iL2rc = m_L2accCnt.begin(); iL2rc != m_L2accCnt.end(); ++iL2rc) { + for (L2accCnt::const_iterator iL2rc = m_L2accCnt.begin(); iL2rc != m_L2accCnt.end(); ++iL2rc) { locality_histo.add2bin(iL2rc->second); - // fprintf(fout, "%#08x:%d\n", iL2rc->first, iL2rc->second); } locality_histo.fprint(fout); fprintf(fout, "\n"); } -L2cacheblk::L2cacheblk(size_t linesize) -: m_mshr(new L2c_mshr(linesize)), - m_missTracker(new L2c_miss_tracker(linesize)), - m_accessLocality(new L2c_access_locality(linesize)) -{ } - -L2cacheblk::~L2cacheblk() +memory_partition_unit::~memory_partition_unit() { delete m_mshr; delete m_missTracker; delete m_accessLocality; } +void memory_partition_unit::set_stats( class memory_stats_t *stats ) +{ + m_stats=stats; + m_dram->set_stats(stats); +} + +void memory_partition_unit::cache_cycle() +{ + L2c_process_dram_output(); // pop from dram + L2c_push_miss_to_dram(); // push to dram + L2c_service_mem_req(); // pop(push) from(to) icnt2l2(l2toicnt) queues; service l2 requests + if (m_config->gpgpu_cache_dl2_opt) { // L2 cache enabled + L2c_update_stat(); + L2c_log(SAMPLELOG); + } +} + +unsigned memory_partition_unit::L2c_get_linesize() +{ + return L2cache->line_sz; +} + +bool memory_partition_unit::full() const +{ + if (m_config->gpgpu_cache_dl2_opt) { + return cbtoL2queue->full() || cbtoL2writequeue->full(); + } else { + return( m_config->gpgpu_dram_sched_queue_size && m_dram->full() ); + } +} //////////////////////////////////////////////// // L2 access functions // L2 Cache Creation -void L2c_create ( dram_t* dram_p, const char* cache_opt ) +memory_partition_unit::memory_partition_unit( unsigned partition_id, struct memory_config *config ) { - unsigned int shd_n_set; - unsigned int shd_linesize; - unsigned int shd_n_assoc; - unsigned char shd_policy; + m_id = partition_id; + m_config=config; + m_stats=NULL; + m_dram = new dram_t(m_id, m_config); + + char L2c_name[32]; + snprintf(L2c_name, 32, "L2_%03d", m_id); + + if( m_config->gpgpu_cache_dl2_opt ) { + L2cache = shd_cache_create(L2c_name,m_config->gpgpu_cache_dl2_opt, 16, ~addrdec_mask[CHIP], write_through); + m_mshr = new L2c_mshr(L2cache->line_sz); + m_missTracker = new L2c_miss_tracker(L2cache->line_sz); + m_accessLocality = new L2c_access_locality(L2cache->line_sz); + } else { + L2cache=NULL; + m_mshr=NULL; + m_missTracker=NULL; + m_accessLocality=NULL; + } unsigned int L2c_cb_L2_length; unsigned int L2c_cb_L2w_length; @@ -388,173 +354,116 @@ void L2c_create ( dram_t* dram_p, const char* cache_opt ) unsigned int L2c_L2_cb_minlength; unsigned int L2c_L2_dm_minlength; - sscanf(cache_opt,"%d:%d:%d:%c", - &shd_n_set, &shd_linesize, &shd_n_assoc, &shd_policy); - - L2cacheblk *p_L2c = new L2cacheblk(shd_linesize); - - char L2c_name[32]; - snprintf(L2c_name, 32, "L2c_%03d", dram_p->id); - p_L2c->L2cache = shd_cache_create(L2c_name, - shd_n_set, shd_n_assoc, shd_linesize, - shd_policy, 16, ~addrdec_mask[CHIP], - write_through); //write_through maintains old behavior for now - - sscanf(gpgpu_L2_queue_config,"%d:%d:%d:%d:%d:%d:%d:%d", + sscanf(m_config->gpgpu_L2_queue_config,"%d:%d:%d:%d:%d:%d:%d:%d", &L2c_cb_L2_length, &L2c_cb_L2w_length, &L2c_L2_dm_length, &L2c_dm_L2_length, &L2c_dm_L2w_length, &L2c_L2_cb_length, &L2c_L2_cb_minlength, &L2c_L2_dm_minlength ); //(<name>,<latency>,<min_length>,<max_length>) - p_L2c->cbtoL2queue = dq_create("cbtoL2queue", 0,0,L2c_cb_L2_length); - p_L2c->cbtoL2writequeue = dq_create("cbtoL2writequeue", 0,0,L2c_cb_L2w_length); - p_L2c->L2todramqueue = dq_create("L2todramqueue", 0,L2c_L2_dm_minlength,L2c_L2_dm_length); - p_L2c->dramtoL2queue = dq_create("dramtoL2queue", 0,0,L2c_dm_L2_length); - p_L2c->dramtoL2writequeue = dq_create("dramtoL2writequeue",0,0,L2c_dm_L2w_length); - p_L2c->L2tocbqueue = dq_create("L2tocbqueue", 0,L2c_L2_cb_minlength,L2c_L2_cb_length); - - p_L2c->L2todram_wbqueue = dq_create("L2todram_wbqueue", 0,L2c_L2_dm_minlength, - L2c_L2_dm_minlength + gpgpu_dram_sched_queue_size + L2c_dm_L2_length); - - p_L2c->L2request = NULL; - - assert(dram_p->m_L2cache == NULL); - dram_p->m_L2cache = reinterpret_cast<void*>(p_L2c); -} - -unsigned L2c_get_linesize( dram_t *dram_p ) -{ - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - return p_L2c->L2cache->line_sz; -} - -int L2c_full( dram_t *dram_p ) -{ - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - return(dq_full(p_L2c->cbtoL2queue) || dq_full(p_L2c->cbtoL2writequeue)); -} - -void L2c_push( dram_t *dram_p, mem_fetch_t *mf ) -{ - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - if (gpgpu_l2_readoverwrite && mf->write) - dq_push(p_L2c->cbtoL2writequeue, mf); - else - dq_push(p_L2c->cbtoL2queue, mf); - p_L2c->m_accessLocality->access(mf); - if (mf->mshr) mshr_update_status(mf->mshr, IN_CBTOL2QUEUE); + cbtoL2queue = new fifo_pipeline<mem_fetch>("cbtoL2queue", 0,L2c_cb_L2_length, gpu_sim_cycle); + cbtoL2writequeue = new fifo_pipeline<mem_fetch>("cbtoL2writequeue", 0,L2c_cb_L2w_length, gpu_sim_cycle); + L2todramqueue = new fifo_pipeline<mem_fetch>("L2todramqueue", L2c_L2_dm_minlength, L2c_L2_dm_length, gpu_sim_cycle); + dramtoL2queue = new fifo_pipeline<mem_fetch>("dramtoL2queue", 0,L2c_dm_L2_length, gpu_sim_cycle); + dramtoL2writequeue = new fifo_pipeline<mem_fetch>("dramtoL2writequeue",0,L2c_dm_L2w_length, gpu_sim_cycle); + L2tocbqueue = new fifo_pipeline<mem_fetch>("L2tocbqueue", L2c_L2_cb_minlength, L2c_L2_cb_length, gpu_sim_cycle); + L2todram_wbqueue = new fifo_pipeline<mem_fetch>("L2todram_wbqueue", L2c_L2_dm_minlength, L2c_L2_dm_minlength + m_config->gpgpu_dram_sched_queue_size + L2c_dm_L2_length, gpu_sim_cycle); + L2request = NULL; + L2dramout = NULL; + wb_addr=-1; + if (m_config->gpgpu_cache_dl2_opt && 1) { + cbtol2_Dist = StatCreate("cbtoL2",1, cbtoL2queue->get_max_len()); + cbtoL2wr_Dist = StatCreate("cbtoL2write",1, cbtoL2writequeue->get_max_len()); + L2tocb_Dist = StatCreate("L2tocb",1, L2tocbqueue->get_max_len()); + dramtoL2_Dist = StatCreate("dramtoL2",1, dramtoL2queue->get_max_len()); + dramtoL2wr_Dist = StatCreate("dramtoL2write",1, dramtoL2writequeue->get_max_len()); + L2todram_Dist = StatCreate("L2todram",1, L2todramqueue->get_max_len()); + L2todram_wb_Dist = StatCreate("L2todram_wb",1, L2todram_wbqueue->get_max_len()); + } else { + cbtol2_Dist = NULL; + cbtoL2wr_Dist = NULL; + L2tocb_Dist = NULL; + dramtoL2_Dist = NULL; + dramtoL2wr_Dist = NULL; + L2todram_Dist = NULL; + L2todram_wb_Dist = NULL; + } } -mem_fetch_t* L2c_pop( dram_t *dram_p ) +mem_fetch* memory_partition_unit::L2c_pop( dram_t *dram_p ) { - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); + assert(dram_p->m_memory_partition_unit != NULL); + memory_partition_unit *p_L2c = reinterpret_cast<memory_partition_unit*>(dram_p->m_memory_partition_unit); - mem_fetch_t *mf; - mf = (mem_fetch_t*)dq_pop(p_L2c->L2tocbqueue); + mem_fetch *mf; + mf = p_L2c->L2tocbqueue->pop(gpu_sim_cycle); return mf; } -mem_fetch_t* L2c_top( dram_t *dram_p ) -{ - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - return (mem_fetch_t*)dq_top(p_L2c->L2tocbqueue); -} - -void L2c_qlen ( dram_t *dram_p ) -{ - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - printf("\n"); - printf("cb->L2{%d}\tcb->L2w{%d}\tL2->cb{%d}\n", - p_L2c->cbtoL2queue->length, - p_L2c->cbtoL2writequeue->length, - p_L2c->L2tocbqueue->length); - printf("dm->L2{%d}\tdm->L2w{%d}\tL2->dm{%d}\tL2->wb_dm{%d}\n", - p_L2c->dramtoL2queue->length, - p_L2c->dramtoL2writequeue->length, - p_L2c->L2todramqueue->length, - p_L2c->L2todram_wbqueue->length); -} - // service memory request in icnt-to-L2 queue, writing to L2 as necessary // (if L2 writeback miss, writeback to memory) -void L2c_service_mem_req ( dram_t* dram_p, int dm_id ) +void memory_partition_unit::L2c_service_mem_req() { - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - mem_fetch_t* mf; - - if (!p_L2c->L2request) { + if (!L2request) { //if not servicing L2 cache request.. - p_L2c->L2request = (mem_fetch_t*) dq_pop(p_L2c->cbtoL2queue); //..then get one - if (!p_L2c->L2request) { - p_L2c->L2request = (mem_fetch_t*) dq_pop(p_L2c->cbtoL2writequeue); - } + L2request = cbtoL2queue->pop(gpu_sim_cycle); //..then get one + if (!L2request) + L2request = cbtoL2writequeue->pop(gpu_sim_cycle); } - mf = p_L2c->L2request; + mem_fetch* mf = L2request; if (!mf) return; switch (mf->type) { case RD_REQ: case WT_REQ: { - shd_cache_line_t *hit_cacheline = shd_cache_access(p_L2c->L2cache, + shd_cache_line_t *hit_cacheline = shd_cache_access(L2cache, mf->addr, - 4, mf->write, + 4, mf->m_write, gpu_sim_cycle); - if (hit_cacheline || l2_ideal) { //L2 Cache Hit; reads are sent as a single command and need to be stored - if (!mf->write) { //L2 Cache Read - if ( dq_full(p_L2c->L2tocbqueue) ) { - p_L2c->L2cache->access--; + if (hit_cacheline || m_config->l2_ideal) { //L2 Cache Hit; reads are sent as a single command and need to be stored + if (!mf->m_write) { //L2 Cache Read + if ( L2tocbqueue->full() ) { + L2cache->access--; } else { mf->type = REPLY_DATA; - dq_push(p_L2c->L2tocbqueue, mf); + L2tocbqueue->push(mf,gpu_sim_cycle); // at this point, should first check if earlier L2 miss is ready to be serviced // if so, service earlier L2 miss first - p_L2c->L2request = NULL; //finished servicing - L2_read_hit++; - memlatstat_icnt2sh_push(mf); - if (mf->mshr) mshr_update_status(mf->mshr, IN_L2TOCBQUEUE_HIT); + L2request = NULL; //finished servicing + m_stats->L2_read_hit++; + m_stats->memlatstat_icnt2sh_push(mf); + if (mf->mshr) mf->mshr->set_status(IN_L2TOCBQUEUE_HIT); } } else { //L2 Cache Write aka servicing L1 Writeback - p_L2c->L2request = NULL; - L2_write_hit++; + L2request = NULL; + m_stats->L2_write_hit++; freed_L1write_mfs++; free(mf); //writeback from L1 successful gpgpu_n_processed_writes++; } } else { // L2 Cache Miss; issue commands accordingly - if ( dq_full(p_L2c->L2todramqueue) ) { - p_L2c->L2cache->miss--; - p_L2c->L2cache->access--; + if ( L2todramqueue->full() ) { + L2cache->miss--; + L2cache->access--; } else { // if a miss hit the mshr, that means there is another inflight request for the same data // this miss just need to access the cache later when this request is serviced - bool mshr_hit = p_L2c->m_mshr->new_miss(mf); + bool mshr_hit = m_mshr->new_miss(mf); if (not mshr_hit) { - if (!mf->write) { - dq_push(p_L2c->L2todramqueue, mf); + if (!mf->m_write) { + L2todramqueue->push(mf,gpu_sim_cycle); } else { // if request is writeback from L1 and misses, // then redirect mf writes to dram (no write allocate) mf->nbytes_L2 = mf->nbytes_L1 - READ_PACKET_SIZE; - dq_push(p_L2c->L2todramqueue, mf); + L2todramqueue->push(mf,gpu_sim_cycle); } } - if (mf->mshr) mshr_update_status(mf->mshr, IN_L2TODRAMQUEUE); - p_L2c->L2request = NULL; + if (mf->mshr) mf->mshr->set_status(IN_L2TODRAMQUEUE); + L2request = NULL; } } } @@ -564,188 +473,135 @@ void L2c_service_mem_req ( dram_t* dram_p, int dm_id ) } // service memory request in L2todramqueue, pushing to dram -void L2c_push_miss_to_dram ( dram_t* dram_p ) +void memory_partition_unit::L2c_push_miss_to_dram() { - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - mem_fetch_t* mf; + if ( m_config->gpgpu_dram_sched_queue_size && m_dram->full() ) + return; - if ( gpgpu_dram_sched_queue_size && dram_full(dram_p) ) return; - - mf = (mem_fetch_t*) dq_pop(p_L2c->L2todram_wbqueue); //prioritize writeback - if (!mf) mf = (mem_fetch_t*) dq_pop(p_L2c->L2todramqueue); + mem_fetch* mf = L2todram_wbqueue->pop(gpu_sim_cycle); //prioritize writeback + if (!mf) mf = L2todramqueue->pop(gpu_sim_cycle); if (mf) { - if (mf->write) { - L2_write_miss++; + if (mf->m_write) { + m_stats->L2_write_miss++; } else { - L2_read_miss++; + m_stats->L2_read_miss++; } - p_L2c->m_missTracker->new_miss(mf); - memlatstat_dram_access(mf, dram_p->id, mf->tlx.bk); - dram_push(dram_p, - mf->tlx.bk, mf->tlx.row, mf->tlx.col, - mf->nbytes_L2, mf->write, - mf->wid, mf->sid, mf->cache_hits_waiting, mf->addr, mf); - if (mf->mshr) mshr_update_status(mf->mshr, IN_DRAM_REQ_QUEUE); + m_missTracker->new_miss(mf); + m_dram->push(mf); + if (mf->mshr) mf->mshr->set_status(IN_DRAM_REQ_QUEUE); } } -//Service writes that are finished in Dram -//only updates the stats and frees the mf -void dramtoL2_service_write(mem_fetch_t * mf) { - freed_L2write_mfs++; - free(mf); - gpgpu_n_processed_writes++; -} - // pop completed memory request from dram and push it to dram-to-L2 queue -void L2c_get_dram_output ( dram_t* dram_p ) +void memory_partition_unit::L2c_get_dram_output () { - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - mem_fetch_t* mf; - mem_fetch_t* mf_top; - if ( dq_full(p_L2c->dramtoL2queue) || dq_full(p_L2c->dramtoL2writequeue) ) return; - mf_top = (mem_fetch_t*) dram_top(dram_p); //test - mf = (mem_fetch_t*) dram_pop(dram_p); + mem_fetch* mf; + mem_fetch* mf_top; + if ( dramtoL2queue->full() || dramtoL2writequeue->full() ) return; + mf_top = m_dram->top(); + mf = m_dram->pop(); assert (mf_top==mf ); if (mf) { - if (gpgpu_l2_readoverwrite && mf->write) - dq_push(p_L2c->dramtoL2writequeue, mf); + if (m_config->gpgpu_l2_readoverwrite && mf->m_write) + dramtoL2writequeue->push(mf,gpu_sim_cycle); else - dq_push(p_L2c->dramtoL2queue, mf); - if (mf->mshr) mshr_update_status(mf->mshr, IN_DRAMTOL2QUEUE); + dramtoL2queue->push(mf,gpu_sim_cycle); + if (mf->mshr) mf->mshr->set_status(IN_DRAMTOL2QUEUE); } } // service memory request in dramtoL2queue, writing to L2 as necessary // (may cause cache eviction and subsequent writeback) -void L2c_process_dram_output ( dram_t* dram_p, int dm_id ) +void memory_partition_unit::L2c_process_dram_output() { - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - static mem_fetch_t **L2dramout = NULL; - static unsigned long long int *wb_addr = NULL; - if (!L2dramout) L2dramout = (mem_fetch_t**)calloc(gpu_n_mem, sizeof(mem_fetch_t*)); - if (!wb_addr) { - wb_addr = (unsigned long long int*)calloc(gpu_n_mem, sizeof(unsigned long long int)); - for (unsigned i = 0; i < gpu_n_mem; i++) wb_addr[i] = -1; - } - - if (L2dramout[dm_id] == NULL) { + if (L2dramout == NULL) { // pop from mshr chain if it is not empty, otherwise, pop a new cacheline from dram output queue - if (p_L2c->m_mshr->mshr_chain_empty() == false) { - L2dramout[dm_id] = p_L2c->m_mshr->mshr_chain_top(); - p_L2c->m_mshr->mshr_chain_pop(); + if (m_mshr->mshr_chain_empty() == false) { + L2dramout = m_mshr->mshr_chain_top(); + m_mshr->mshr_chain_pop(); } else { - L2dramout[dm_id] = (mem_fetch_t*) dq_pop(p_L2c->dramtoL2queue); - if (!L2dramout[dm_id]) L2dramout[dm_id] = (mem_fetch_t*) dq_pop(p_L2c->dramtoL2writequeue); + L2dramout = dramtoL2queue->pop(gpu_sim_cycle); + if (!L2dramout) L2dramout = dramtoL2writequeue->pop(gpu_sim_cycle); - if (L2dramout[dm_id] != NULL) { - p_L2c->m_mshr->miss_serviced(L2dramout[dm_id]); + if (L2dramout != NULL) { + m_mshr->miss_serviced(L2dramout); - if (p_L2c->m_mshr->mshr_chain_empty() == false) { // possible if this is a L2 writeback - L2dramout[dm_id] = p_L2c->m_mshr->mshr_chain_top(); - p_L2c->m_mshr->mshr_chain_pop(); + if (m_mshr->mshr_chain_empty() == false) { // possible if this is a L2 writeback + L2dramout = m_mshr->mshr_chain_top(); + m_mshr->mshr_chain_pop(); } } } } - mem_fetch_t* mf = L2dramout[dm_id]; + mem_fetch* mf = L2dramout; if (mf) { - if (!mf->write) { //service L2 read miss + if (!mf->m_write) { //service L2 read miss // it is a pre-fill dramout mf - if (wb_addr[dm_id] == (unsigned long long int)-1) { - if ( dq_full(p_L2c->L2tocbqueue) ) goto RETURN; + if (wb_addr == (unsigned long long int)-1) { + if ( L2tocbqueue->full() ) goto RETURN; - if (mf->mshr) mshr_update_status(mf->mshr, IN_L2TOCBQUEUE_MISS); + if (mf->mshr) mf->mshr->set_status(IN_L2TOCBQUEUE_MISS); //only transfer across icnt once the whole line has been received by L2 cache mf->type = REPLY_DATA; - dq_push(p_L2c->L2tocbqueue, mf); + L2tocbqueue->push(mf,gpu_sim_cycle); - assert(mf->sid <= (int)gpu_n_shader); - shd_cache_line_t *fetch_line_exist = shd_cache_probe(p_L2c->L2cache, mf->addr); + shd_cache_line_t *fetch_line_exist = shd_cache_probe(L2cache, mf->addr); if (fetch_line_exist == NULL) { - wb_addr[dm_id] = L2_shd_cache_fill(p_L2c->L2cache, mf->addr, gpu_sim_cycle ); + wb_addr = L2_shd_cache_fill(L2cache, mf->addr, gpu_sim_cycle ); } } // only perform a write on cache eviction (write-back policy) // it is the 1st or nth time trial to writeback - if (wb_addr[dm_id] != (unsigned long long int)-1) { + if (wb_addr != (unsigned long long int)-1) { // performing L2 writeback (no false sharing for memory-side cache) - int wb_succeed = L2c_write_back(wb_addr[dm_id], p_L2c->L2cache->line_sz, dm_id ); + int wb_succeed = L2c_write_back(wb_addr, L2cache->line_sz); if (!wb_succeed) goto RETURN; //try again next cycle } - p_L2c->m_missTracker->miss_serviced(mf); - L2dramout[dm_id] = NULL; - wb_addr[dm_id] = -1; + m_missTracker->miss_serviced(mf); + L2dramout = NULL; + wb_addr = -1; } else { //service L2 write miss - p_L2c->m_missTracker->miss_serviced(mf); - dramtoL2_service_write(mf); - L2dramout[dm_id] = NULL; - wb_addr[dm_id] = -1; + m_missTracker->miss_serviced(mf); + freed_L2write_mfs++; + free(mf); + gpgpu_n_processed_writes++; + L2dramout = NULL; + wb_addr = -1; } } RETURN: - assert (L2dramout[dm_id] || wb_addr[dm_id] == (unsigned long long int)-1); + assert (L2dramout || wb_addr == (unsigned long long int)-1); } // Writeback from L2 to DRAM: // - Takes in memory address and their parameters and pushes to dram request queue // - This is used only for L2 writeback -unsigned char L2c_write_back(unsigned long long int addr, int bsize, int dram_id ) +bool memory_partition_unit::L2c_write_back( unsigned long long int addr, int bsize ) { - addrdec_t tlx; - addrdec_tlx(addr,&tlx); - - assert(dram[dram_id]->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[dram_id]->m_L2cache); - - if ( dq_full(p_L2c->L2todram_wbqueue) ) return 0; - - mem_fetch_t *mf; - - mf = (mem_fetch_t*) malloc(sizeof(mem_fetch_t)); + if ( L2todram_wbqueue->full() ) + return false; + mem_fetch *mf = new mem_fetch(addr, + bsize+READ_PACKET_SIZE/*l1*/, + bsize/*l2*/, + 0/*sid*/,0/*tpc*/,0/*wid*/,0/*cache_hits_waiting*/,NULL,true, + partial_write_mask_t(), + L2_WRBK_ACC, + L2_WTBK_DATA, + -1/*pc*/); + m_stats->memlatstat_start(mf); made_write_mfs++; - mf->request_uid = g_next_mf_request_uid++; - mf->addr = addr; - mf->nbytes_L1 = bsize + READ_PACKET_SIZE; - mf->txbytes_L1 = 0; - mf->rxbytes_L1 = 0; - mf->nbytes_L2 = bsize; - mf->sid = gpu_n_shader; // (gpu_n_shader+1); - mf->wid = 0; - mf->txbytes_L2 = 0; - mf->rxbytes_L2 = 0; - mf->mshr = NULL; - mf->pc = -1; // disable ptx_file_line_stats - mf->write = 1; // it is writeback - mf->mem_acc = L2_WRBK_ACC; - memlatstat_start(mf); - mf->tlx = tlx; - mf->bank = mf->tlx.bk; - mf->chip = mf->tlx.chip; - - - //writeback - mf->type = L2_WTBK_DATA; - if (!dq_push(p_L2c->L2todram_wbqueue, mf)) assert(0); + L2todram_wbqueue->push(mf,gpu_sim_cycle); gpgpu_n_sent_writes++; - return 1; + return true; } -unsigned int L2c_cache_flush ( dram_t* dram_p) { - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - shd_cache_t *cp = p_L2c->L2cache; +unsigned int memory_partition_unit::L2c_cache_flush() +{ + shd_cache_t *cp = L2cache; int dirty_lines_flushed = 0 ; for (unsigned i = 0; i < cp->nset * cp->assoc ; i++) { if ( (cp->lines[i].status & (DIRTY|VALID)) == (DIRTY|VALID) ) { @@ -757,158 +613,141 @@ unsigned int L2c_cache_flush ( dram_t* dram_p) { return dirty_lines_flushed; } -void L2c_init_stat() +void memory_partition_unit::L2c_print_cache_stat(unsigned &accesses, unsigned &misses) const { - L2_cbtoL2length = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int)); - L2_cbtoL2writelength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int)); - L2_L2tocblength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int)); - L2_dramtoL2length = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int)); - L2_dramtoL2writelength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int)); - L2_L2todramlength = (unsigned int*) calloc(gpu_n_mem, sizeof(unsigned int)); + FILE *fp = stdout; + shd_cache_print(L2cache,fp,accesses,misses); + m_mshr->print_stat(fp); + m_missTracker->print_stat(fp); + m_accessLocality->print_stat(fp, false); } -void L2c_update_stat( dram_t* dram_p) +void memory_partition_unit::L2c_update_stat() { - assert(dram_p->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram_p->m_L2cache); - - int i = dram_p->id; - - if (p_L2c->cbtoL2queue->length > L2_cbtoL2length[i]) - L2_cbtoL2length[i] = p_L2c->cbtoL2queue->length; - if (p_L2c->cbtoL2writequeue->length > L2_cbtoL2writelength[i]) - L2_cbtoL2writelength[i] = p_L2c->cbtoL2writequeue->length; - if (p_L2c->L2tocbqueue->length > L2_L2tocblength[i]) - L2_L2tocblength[i] = p_L2c->L2tocbqueue->length; - if (p_L2c->dramtoL2queue->length > L2_dramtoL2length[i]) - L2_dramtoL2length[i] = p_L2c->dramtoL2queue->length; - if (p_L2c->dramtoL2writequeue->length > L2_dramtoL2writelength[i]) - L2_dramtoL2writelength[i] = p_L2c->dramtoL2writequeue->length; - if (p_L2c->L2todramqueue->length > L2_L2todramlength[i]) - L2_L2todramlength[i] = p_L2c->L2todramqueue->length; + unsigned i=m_id; + if (cbtoL2queue->get_length() > m_stats->L2_cbtoL2length[i]) + m_stats->L2_cbtoL2length[i] = cbtoL2queue->get_length(); + if (cbtoL2writequeue->get_length() > m_stats->L2_cbtoL2writelength[i]) + m_stats->L2_cbtoL2writelength[i] = cbtoL2writequeue->get_length(); + if (L2tocbqueue->get_length() > m_stats->L2_L2tocblength[i]) + m_stats->L2_L2tocblength[i] = L2tocbqueue->get_length(); + if (dramtoL2queue->get_length() > m_stats->L2_dramtoL2length[i]) + m_stats->L2_dramtoL2length[i] = dramtoL2queue->get_length(); + if (dramtoL2writequeue->get_length() > m_stats->L2_dramtoL2writelength[i]) + m_stats->L2_dramtoL2writelength[i] = dramtoL2writequeue->get_length(); + if (L2todramqueue->get_length() > m_stats->L2_L2todramlength[i]) + m_stats->L2_L2todramlength[i] = L2todramqueue->get_length(); } -void L2c_print_stat( ) +void memory_stats_t::L2c_print_stat( unsigned n_mem ) { unsigned i; printf(" "); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<n_mem;i++) { printf(" dram[%d]", i); } printf("\n"); printf("cbtoL2 queue maximum length ="); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<n_mem;i++) { printf("%8d", L2_cbtoL2length[i]); } printf("\n"); printf("cbtoL2 write queue maximum length ="); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<n_mem;i++) { printf("%8d", L2_cbtoL2writelength[i]); } printf("\n"); printf("L2tocb queue maximum length ="); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<n_mem;i++) { printf("%8d", L2_L2tocblength[i]); } printf("\n"); printf("dramtoL2 queue maximum length ="); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<n_mem;i++) { printf("%8d", L2_dramtoL2length[i]); } printf("\n"); printf("dramtoL2 write queue maximum length ="); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<n_mem;i++) { printf("%8d", L2_dramtoL2writelength[i]); } printf("\n"); printf("L2todram queue maximum length ="); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<n_mem;i++) { printf("%8d", L2_L2todramlength[i]); } printf("\n"); } -void L2c_print_cache_stat() +void memory_stats_t::print( FILE *fp ) { - unsigned i; - int j, k; - for (i=0,j=0,k=0;i<gpu_n_mem;i++) { - assert(dram[i]->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); + fprintf(fp,"L2_write_miss = %d\n", L2_write_miss); + fprintf(fp,"L2_write_hit = %d\n", L2_write_hit); + fprintf(fp,"L2_read_miss = %d\n", L2_read_miss); + fprintf(fp,"L2_read_hit = %d\n", L2_read_hit); +} - shd_cache_print(p_L2c->L2cache,stdout); - j += p_L2c->L2cache->miss; - k += p_L2c->L2cache->access; - p_L2c->m_mshr->print_stat(stdout); - p_L2c->m_missTracker->print_stat(stdout); - p_L2c->m_accessLocality->print_stat(stdout, false); - } +void gpgpu_sim::L2c_print_cache_stat() const +{ + unsigned i, j, k; + for (i=0,j=0,k=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->L2c_print_cache_stat(k,j); printf("L2 Cache Total Miss Rate = %0.3f\n", (float)j/k); } -void L2c_print_debug( ) +void gpgpu_sim::L2c_print_debug() { unsigned i; printf(" "); - for (i=0;i<gpu_n_mem;i++) { + for (i=0;i<m_n_mem;i++) printf(" dram[%d]", i); - } printf("\n"); printf("cbtoL2 queue length ="); - for (i=0;i<gpu_n_mem;i++) { - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - printf("%8d", p_L2c->cbtoL2queue->length); - } + for (i=0;i<m_n_mem;i++) + printf("%8d", m_memory_partition_unit[i]->get_cbtoL2queue_length() ); printf("\n"); printf("cbtoL2 write queue length ="); - for (i=0;i<gpu_n_mem;i++) { - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - printf("%8d", p_L2c->cbtoL2writequeue->length); - } + for (i=0;i<m_n_mem;i++) + printf("%8d", m_memory_partition_unit[i]->get_cbtoL2writequeue_length()); printf("\n"); printf("L2tocb queue length ="); - for (i=0;i<gpu_n_mem;i++) { - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - printf("%8d", p_L2c->L2tocbqueue->length); + for (i=0;i<m_n_mem;i++) { + printf("%8d", m_memory_partition_unit[i]->get_L2tocbqueue_length()); } printf("\n"); printf("dramtoL2 queue length ="); - for (i=0;i<gpu_n_mem;i++) { - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - printf("%8d", p_L2c->dramtoL2queue->length); + for (i=0;i<m_n_mem;i++) { + printf("%8d", m_memory_partition_unit[i]->get_dramtoL2queue_length()); } printf("\n"); printf("dramtoL2 write queue length ="); - for (i=0;i<gpu_n_mem;i++) { - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - printf("%8d", p_L2c->dramtoL2writequeue->length); + for (i=0;i<m_n_mem;i++) { + printf("%8d", m_memory_partition_unit[i]->get_dramtoL2writequeue_length()); } printf("\n"); printf("L2todram queue length ="); - for (i=0;i<gpu_n_mem;i++) { - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - printf("%8d", p_L2c->L2todramqueue->length); + for (i=0;i<m_n_mem;i++) { + printf("%8d", m_memory_partition_unit[i]->get_L2todramqueue_length()); } printf("\n"); printf("L2todram writeback queue length ="); - for (i=0;i<gpu_n_mem;i++) { - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - printf("%8d", p_L2c->L2todram_wbqueue->length); + for (i=0;i<m_n_mem;i++) { + printf("%8d", m_memory_partition_unit[i]->get_L2todram_wbqueue_length()); } printf("\n"); } @@ -917,78 +756,55 @@ void L2c_print_debug( ) #define SAMPLELOG 222 #define DUMPLOG 333 -void L2c_log(int task) +void memory_partition_unit::L2c_log(int task) { - unsigned i; - static void ** cbtol2_Dist ; - static void ** cbtoL2wr_Dist ; - static void ** L2tocb_Dist ; - static void ** dramtoL2_Dist ; - static void ** dramtoL2wr_Dist ; - static void ** L2todram_Dist ; - static void ** L2todram_wb_Dist ; - if (task == CREATELOG) { - cbtol2_Dist = (void **) calloc(gpu_n_mem,sizeof(void*)); - cbtoL2wr_Dist = (void **) calloc(gpu_n_mem,sizeof(void*)); - L2tocb_Dist = (void **) calloc(gpu_n_mem,sizeof(void*)); - dramtoL2_Dist = (void **)calloc(gpu_n_mem,sizeof(void*)); - dramtoL2wr_Dist = (void **)calloc(gpu_n_mem,sizeof(void*)); - L2todram_Dist = (void **)calloc(gpu_n_mem,sizeof(void*)); - L2todram_wb_Dist = (void **)calloc(gpu_n_mem,sizeof(void*)); - - for (i=0;i<gpu_n_mem;i++) { - assert(dram[i]->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - - cbtol2_Dist[i] = StatCreate("cbtoL2",1,p_L2c->cbtoL2queue->max_len); - cbtoL2wr_Dist[i] = StatCreate("cbtoL2write",1,p_L2c->cbtoL2writequeue->max_len); - L2tocb_Dist[i] = StatCreate("L2tocb",1,p_L2c->L2tocbqueue->max_len); - dramtoL2_Dist[i] = StatCreate("dramtoL2",1,p_L2c->dramtoL2queue->max_len); - dramtoL2wr_Dist[i] = StatCreate("dramtoL2write",1,p_L2c->dramtoL2writequeue->max_len); - L2todram_Dist[i] = StatCreate("L2todram",1,p_L2c->L2todramqueue->max_len); - L2todram_wb_Dist[i] = StatCreate("L2todram_wb",1,p_L2c->L2todram_wbqueue->max_len); - } - } else if (task == SAMPLELOG) { - for (i=0;i<gpu_n_mem;i++) { - assert(dram[i]->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); - - StatAddSample(cbtol2_Dist[i], p_L2c->cbtoL2queue->length); - StatAddSample(cbtoL2wr_Dist[i], p_L2c->cbtoL2writequeue->length); - StatAddSample(L2tocb_Dist[i], p_L2c->L2tocbqueue->length); - StatAddSample(dramtoL2_Dist[i], p_L2c->dramtoL2queue->length); - StatAddSample(dramtoL2wr_Dist[i], p_L2c->dramtoL2writequeue->length); - StatAddSample(L2todram_Dist[i], p_L2c->L2todramqueue->length); - StatAddSample(L2todram_wb_Dist[i], p_L2c->L2todram_wbqueue->length); - } + if (task == SAMPLELOG) { + StatAddSample(cbtol2_Dist, cbtoL2queue->get_length()); + StatAddSample(cbtoL2wr_Dist, cbtoL2writequeue->get_length()); + StatAddSample(L2tocb_Dist, L2tocbqueue->get_length()); + StatAddSample(dramtoL2_Dist, dramtoL2queue->get_length()); + StatAddSample(dramtoL2wr_Dist, dramtoL2writequeue->get_length()); + StatAddSample(L2todram_Dist, L2todramqueue->get_length()); + StatAddSample(L2todram_wb_Dist, L2todram_wbqueue->get_length()); } else if (task == DUMPLOG) { - for (i=0;i<gpu_n_mem;i++) { - printf ("Queue Length DRAM[%d] ",i); StatDisp(cbtol2_Dist[i]); - printf ("Queue Length DRAM[%d] ",i); StatDisp(cbtoL2wr_Dist[i]); - printf ("Queue Length DRAM[%d] ",i); StatDisp(L2tocb_Dist[i]); - printf ("Queue Length DRAM[%d] ",i); StatDisp(dramtoL2_Dist[i]); - printf ("Queue Length DRAM[%d] ",i); StatDisp(dramtoL2wr_Dist[i]); - printf ("Queue Length DRAM[%d] ",i); StatDisp(L2todram_Dist[i]); - printf ("Queue Length DRAM[%d] ",i); StatDisp(L2todram_wb_Dist[i]); - } + printf ("Queue Length DRAM[%d] ",m_id); StatDisp(cbtol2_Dist); + printf ("Queue Length DRAM[%d] ",m_id); StatDisp(cbtoL2wr_Dist); + printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2tocb_Dist); + printf ("Queue Length DRAM[%d] ",m_id); StatDisp(dramtoL2_Dist); + printf ("Queue Length DRAM[%d] ",m_id); StatDisp(dramtoL2wr_Dist); + printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2todram_Dist); + printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2todram_wb_Dist); } } -void L2c_latency_log_dump() +void gpgpu_sim::L2c_latency_log_dump() { - unsigned i; - for (i=0;i<gpu_n_mem;i++) { - assert(dram[i]->m_L2cache != NULL); - L2cacheblk *p_L2c = reinterpret_cast<L2cacheblk*>(dram[i]->m_L2cache); + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->L2c_latency_log_dump(); +} - printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->cbtoL2queue->lat_stat); - printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->cbtoL2writequeue->lat_stat); - printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->L2tocbqueue->lat_stat); - printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->dramtoL2queue->lat_stat); - printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->dramtoL2writequeue->lat_stat); - printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->L2todramqueue->lat_stat); - printf ("(LOGB2)Latency DRAM[%d] ",i); StatDisp(p_L2c->L2todram_wbqueue->lat_stat); - } +void memory_partition_unit::L2c_latency_log_dump() +{ + printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(cbtoL2queue->get_lat_stat()); + printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(cbtoL2writequeue->get_lat_stat()); + printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2tocbqueue->get_lat_stat()); + printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(dramtoL2queue->get_lat_stat()); + printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(dramtoL2writequeue->get_lat_stat()); + printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2todramqueue->get_lat_stat()); + printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2todram_wbqueue->get_lat_stat()); +} + +bool memory_partition_unit::busy() const +{ + return !m_request_tracker.empty(); } +void memory_partition_unit::request_tracker_insert(class mem_fetch *mf) +{ + m_request_tracker.insert(mf); +} +void memory_partition_unit::request_tracker_erase(class mem_fetch *mf) +{ + m_request_tracker.erase(mf); +} diff --git a/src/gpgpu-sim/l2cache.h b/src/gpgpu-sim/l2cache.h index 6566dd7..55202ee 100644 --- a/src/gpgpu-sim/l2cache.h +++ b/src/gpgpu-sim/l2cache.h @@ -1,53 +1,278 @@ -#pragma once +/* + * l2cache.h + * + * Copyright (c) 2009 by Tor M. Aamodt and + * University of British Columbia + * Vancouver, BC V6T 1Z4 + * All Rights Reserved. + * + * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE + * TERMS AND CONDITIONS. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h + * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda + * (property of NVIDIA). The files benchmarks/BlackScholes/ and + * benchmarks/template/ are derived from the CUDA SDK available from + * http://www.nvidia.com/cuda (also property of NVIDIA). The files from + * src/intersim/ are derived from Booksim (a simulator provided with the + * textbook "Principles and Practices of Interconnection Networks" available + * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by + * the corresponding legal terms and conditions set forth separately (original + * copyright notices are left in files from these sources and where we have + * modified a file our copyright notice appears before the original copyright + * notice). + * + * Using this version of GPGPU-Sim requires a complete installation of CUDA + * which is distributed seperately by NVIDIA under separate terms and + * conditions. To use this version of GPGPU-Sim with OpenCL requires a + * recent version of NVIDIA's drivers which support OpenCL. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the University of British Columbia nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. + * + * 5. No nonprofit user may place any restrictions on the use of this software, + * including as modified by the user, by any other authorized user. + * + * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, + * Ali Bakhoda, George L. Yuan, at the University of British Columbia, + * Vancouver, BC V6T 1Z4 + */ + +#ifndef MC_PARTITION_INCLUDED +#define MC_PARTITION_INCLUDED #include "dram.h" +#include "../tr1_hash_map.h" +#include "../abstract_hardware_model.h" + +#include <list> +#include <queue> + +class mem_fetch; + +class L2c_mshr +{ +private: + typedef std::list<const mem_fetch*> mem_fetch_list; + typedef tr1_hash_map<address_type, mem_fetch_list> L2missGroup; + L2missGroup m_L2missgroup; // structure tracking redundant dram access + + struct active_chain { + address_type cacheTag; + mem_fetch_list *list; + active_chain() : cacheTag(0xDEADBEEF), list(NULL) { } + }; + active_chain m_active_mshr_chain; + size_t m_linesize; // L2 cache line size + + const size_t m_n_entries; // total number of entries available + size_t m_entries_used; // number of entries in use + + int m_n_miss; + int m_n_miss_serviced_by_dram; + int m_n_mshr_hits; + size_t m_max_entries_used; + + address_type cache_tag(const mem_fetch *mf) const; + +public: + L2c_mshr(size_t linesize, size_t n_entries = 64) + : m_linesize(linesize), m_n_entries(n_entries), m_entries_used(0), + m_n_miss(0), m_n_miss_serviced_by_dram(0), m_n_mshr_hits(0), m_max_entries_used(0) { } + + // add a cache miss to MSHR, return true if this access is hit another existing entry and merges with it + bool new_miss(const mem_fetch *mf); + + // notify MSHR that a new cache line has been fetched, activate the associated MSHR chain + void miss_serviced(const mem_fetch *mf); + + // probe if there are pending hits left in this MSHR chain + bool mshr_chain_empty(); + + // peek the first entry in the active MSHR chain + mem_fetch *mshr_chain_top(); + + // pop the first entry in the active MSHR chain + void mshr_chain_pop(); + + void print(FILE *fout = stdout); + void print_stat(FILE *fout = stdout) const; +}; + +class L2c_miss_tracker +{ +private: + typedef std::set<mem_fetch*> mem_fetch_set; + typedef tr1_hash_map<address_type, mem_fetch_set> L2missGroup; + L2missGroup m_L2missgroup; // structure tracking redundant dram access + size_t m_linesize; // L2 cache line size + + typedef tr1_hash_map<address_type, int> L2redundantCnt; + L2redundantCnt m_L2redundantCnt; + + int m_totalL2redundantAcc; + + address_type cache_tag(const mem_fetch *mf) const; + +public: + L2c_miss_tracker(size_t linesize) : m_linesize(linesize), m_totalL2redundantAcc(0) { } + void new_miss(mem_fetch *mf); + void miss_serviced(mem_fetch *mf); + + void print(FILE *fout, bool brief = true); + void print_stat(FILE *fout, bool brief = true) const; +}; + +class L2c_access_locality +{ +public: + L2c_access_locality(size_t linesize) : m_linesize(linesize), m_totalL2accAcc(0) { } + void print_stat(FILE *fout, bool brief = true) const; + void access(mem_fetch *mf); +private: + address_type cache_tag(const mem_fetch *mf) const; + + size_t m_linesize; // L2 cache line size + + typedef tr1_hash_map<address_type, int> L2accCnt; + L2accCnt m_L2accCnt; + int m_totalL2accAcc; +}; + +class memory_partition_unit +{ +public: + memory_partition_unit( unsigned partition_id, struct memory_config *config); + ~memory_partition_unit(); + + void set_stats( class memory_stats_t *stats ); + + void cache_cycle(); + + bool has_cache() { return L2cache != NULL; } + unsigned L2c_get_linesize(); + bool full() const; + bool busy() const; + + void push( class mem_fetch* mf, unsigned long long clock_cycle ); + class mem_fetch* pop(); + class mem_fetch* top(); + void issueCMD(); + void visualizer_print( gzFile visualizer_file ); + void L2c_latency_log_dump(); + void L2c_log(int task); + unsigned L2c_cache_flush(); + void L2c_print_cache_stat(unsigned &accesses, unsigned &misses) const; + + unsigned get_cbtoL2queue_length() const { return cbtoL2queue->get_length(); } + unsigned get_cbtoL2writequeue_length() const { return cbtoL2writequeue->get_length(); } + unsigned get_dramtoL2queue_length() const { return dramtoL2queue->get_length(); } + unsigned get_dramtoL2writequeue_length() const { return dramtoL2writequeue->get_length(); } + unsigned get_L2todramqueue_length() const { return L2todramqueue->get_length(); } + unsigned get_L2todram_wbqueue_length() const { return L2todram_wbqueue->get_length(); } + unsigned get_L2tocbqueue_length() const { return L2tocbqueue->get_length(); } + + void print_stat( FILE *fp ) { m_dram->print_stat(fp); } + void visualize() const { m_dram->visualize(); } + unsigned dram_que_length() const { return m_dram->que_length(); } + void queue_latency_log_dump( FILE *fp ) { m_dram->queue_latency_log_dump(fp); } + void print( FILE *fp ) { m_dram->print(fp); } -// L2 Cache Creation -void L2c_create ( dram_t* dram_p, const char* cache_opt ); +private: + void request_tracker_insert(class mem_fetch *mf); + void request_tracker_erase(class mem_fetch *mf); -void L2c_qlen ( dram_t *dram_p ); + // pop completed memory request from dram and push it to dram-to-L2 queue + void L2c_get_dram_output(); -// service memory request in icnt-to-L2 queue, writing to L2 as necessary -// (if L2 writeback miss, writeback to memory) -void L2c_service_mem_req ( dram_t* dram_p, int dm_id ); + // service memory request in icnt-to-L2 queue, writing to L2 as necessary + // (if L2 writeback miss, writeback to memory) + void L2c_service_mem_req(); + + // service memory request in L2todramqueue, pushing to dram + void L2c_push_miss_to_dram(); + + // service memory request in dramtoL2queue, writing to L2 as necessary + // (may cause cache eviction and subsequent writeback) + void L2c_process_dram_output(); + + bool L2c_write_back( unsigned long long int addr, int bsize ); + + // probe L2 cache for fullness + struct mem_fetch* L2c_pop( dram_t *dram_p ); + + void L2c_init_stat(unsigned n_mem); + void L2c_update_stat(); + void L2c_print_debug(); -// service memory request in L2todramqueue, pushing to dram -void L2c_push_miss_to_dram ( dram_t* dram_p ); +// data + unsigned m_id; + struct memory_config *m_config; + class dram_t *m_dram; + struct shd_cache_t *L2cache; -// pop completed memory request from dram and push it to dram-to-L2 queue -void L2c_get_dram_output ( dram_t* dram_p ); + // model delay of ROP units with a fixed latency + struct rop_delay_t + { + unsigned long long ready_cycle; + class mem_fetch* req; + }; + std::queue<rop_delay_t> m_rop; -// service memory request in dramtoL2queue, writing to L2 as necessary -// (may cause cache eviction and subsequent writeback) -void L2c_process_dram_output ( dram_t* dram_p, int dm_id ); + // these are various FIFOs between units within a memory partition + fifo_pipeline<mem_fetch> *cbtoL2queue; + fifo_pipeline<mem_fetch> *cbtoL2writequeue; + fifo_pipeline<mem_fetch> *dramtoL2queue; + fifo_pipeline<mem_fetch> *dramtoL2writequeue; + fifo_pipeline<mem_fetch> *L2todramqueue; + fifo_pipeline<mem_fetch> *L2todram_wbqueue; + fifo_pipeline<mem_fetch> *L2tocbqueue; -// Writeback from L2 to DRAM: -// - Takes in memory address and their parameters and pushes to dram request queue -// - This is used only for L2 writeback -unsigned char L2c_write_back(unsigned long long int addr, int bsize, int dram_id ); + mem_fetch *L2request; //request currently being serviced by the L2 Cache -unsigned int L2c_cache_flush ( dram_t* dram_p); + L2c_mshr *m_mshr; // mshr model + L2c_miss_tracker *m_missTracker; // tracker observing for redundant misses + L2c_access_locality *m_accessLocality; // tracking true locality of L2 Cache access -unsigned L2c_get_linesize( dram_t *dram_p ); + class mem_fetch *L2dramout; + unsigned long long int wb_addr; -// probe L2 cache for fullness -int L2c_full( dram_t *dram_p ); -void L2c_push( dram_t *dram_p, struct mem_fetch *mf ); -struct mem_fetch* L2c_pop( dram_t *dram_p ); -struct mem_fetch* L2c_top( dram_t *dram_p ); + class memory_stats_t *m_stats; -void L2c_init_stat(); -void L2c_update_stat( dram_t* dram_p); -void L2c_print_stat(); -void L2c_print_cache_stat(); -void L2c_print_debug(); -void L2c_log(int task); -void L2c_latency_log_dump(); + class Stats *cbtol2_Dist; + class Stats *cbtoL2wr_Dist; + class Stats *L2tocb_Dist; + class Stats *dramtoL2_Dist; + class Stats *dramtoL2wr_Dist; + class Stats *L2todram_Dist; + class Stats *L2todram_wb_Dist; -void L2c_options(class OptionParser *opp); + std::set<mem_fetch*> m_request_tracker; +}; -extern unsigned L2_write_miss; -extern unsigned L2_write_hit; -extern unsigned L2_read_hit; -extern unsigned L2_read_miss; -extern bool gpgpu_l2_readoverwrite; +#endif diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc new file mode 100644 index 0000000..99a1e58 --- /dev/null +++ b/src/gpgpu-sim/mem_fetch.cc @@ -0,0 +1,106 @@ +/* + * mem_fetch.cc + * + * Copyright (c) 2009 by Tor M. Aamodt and + * University of British Columbia + * Vancouver, BC V6T 1Z4 + * All Rights Reserved. + * + * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE + * TERMS AND CONDITIONS. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h + * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda + * (property of NVIDIA). The files benchmarks/BlackScholes/ and + * benchmarks/template/ are derived from the CUDA SDK available from + * http://www.nvidia.com/cuda (also property of NVIDIA). The files from + * src/intersim/ are derived from Booksim (a simulator provided with the + * textbook "Principles and Practices of Interconnection Networks" available + * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by + * the corresponding legal terms and conditions set forth separately (original + * copyright notices are left in files from these sources and where we have + * modified a file our copyright notice appears before the original copyright + * notice). + * + * Using this version of GPGPU-Sim requires a complete installation of CUDA + * which is distributed seperately by NVIDIA under separate terms and + * conditions. To use this version of GPGPU-Sim with OpenCL requires a + * recent version of NVIDIA's drivers which support OpenCL. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the University of British Columbia nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. + * + * 5. No nonprofit user may place any restrictions on the use of this software, + * including as modified by the user, by any other authorized user. + * + * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, + * Ali Bakhoda, George L. Yuan, at the University of British Columbia, + * Vancouver, BC V6T 1Z4 + */ + +#include "mem_fetch.h" +#include "mem_latency_stat.h" + +unsigned mem_fetch::sm_next_mf_request_uid=1; + +mem_fetch::mem_fetch( unsigned long long int addr, + int l1bsize, + int l2bsize, + int sid, + unsigned tpc, + int wid, + int cache_hits_waiting, + class mshr_entry * mshr, + bool write, + partial_write_mask_t partial_write_mask, + enum mem_access_type mem_acc, + enum mf_type type, + address_type pc ) +{ + class mem_fetch *mf = this; + mf->request_uid = sm_next_mf_request_uid++; + mf->addr = addr; + mf->nbytes_L1 = l1bsize; + mf->nbytes_L2 = l2bsize; + mf->sid = sid; + mf->wid = wid; + mf->cache_hits_waiting = cache_hits_waiting; + mf->txbytes_L1 = 0; + mf->rxbytes_L1 = 0; + mf->mshr = mshr; + mf->m_write = write; + addrdec_tlx(addr,&mf->tlx); + mf->bank = mf->tlx.bk; + mf->chip = mf->tlx.chip; + mf->txbytes_L2 = 0; + mf->rxbytes_L2 = 0; + mf->write_mask = partial_write_mask; + mf->mem_acc = mem_acc; + mf->type = type; + mf->pc = pc; +} diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h index 1db348a..7196690 100644 --- a/src/gpgpu-sim/mem_fetch.h +++ b/src/gpgpu-sim/mem_fetch.h @@ -67,9 +67,9 @@ #ifndef MEM_FETCH_H #define MEM_FETCH_H -#include "shader.h" #include "addrdec.h" #include "../abstract_hardware_model.h" +#include <bitset> enum mf_type { RD_REQ = 0, @@ -80,7 +80,38 @@ enum mf_type { N_MF_TYPE }; -typedef struct mem_fetch { +enum mem_access_type { + GLOBAL_ACC_R = 0, + LOCAL_ACC_R = 1, + CONST_ACC_R = 2, + TEXTURE_ACC_R = 3, + GLOBAL_ACC_W = 4, + LOCAL_ACC_W = 5, + L2_WRBK_ACC = 6, + INST_ACC_R = 7, + NUM_MEM_ACCESS_TYPE = 8 +}; + +const unsigned partial_write_mask_bits = 128; //must be at least size of largest memory access. +typedef std::bitset<partial_write_mask_bits> partial_write_mask_t; + +class mem_fetch { +public: + mem_fetch( unsigned long long int addr, + int l1bsize, + int l2bsize, + int sid, + unsigned tpc, + int wid, + int cache_hits_waiting, + class mshr_entry * mshr, + bool write, + partial_write_mask_t partial_write_mask, + enum mem_access_type mem_acc, + enum mf_type type, + address_type pc ); + +public: unsigned request_uid; unsigned long long int addr; int nbytes_L1; @@ -92,9 +123,9 @@ typedef struct mem_fetch { int sid; //shader core id int wid; //warp id int cache_hits_waiting; - mshr_entry* mshr; + class mshr_entry* mshr; address_type pc; - unsigned char write; + bool m_write; enum mem_access_type mem_acc; unsigned int timestamp; //set to gpu_sim_cycle at struct creation unsigned int timestamp2; //set to gpu_sim_cycle when pushed onto icnt to shader; only used for reads @@ -104,8 +135,7 @@ typedef struct mem_fetch { addrdec_t tlx; enum mf_type type; partial_write_mask_t write_mask; - int source_node; //memory node id when sending from mem to shader - //same as sid when sending from shader 2 mem -} mem_fetch_t; + static unsigned sm_next_mf_request_uid; +}; #endif diff --git a/src/gpgpu-sim/mem_latency_stat.cc b/src/gpgpu-sim/mem_latency_stat.cc index f225087..cd1a650 100644 --- a/src/gpgpu-sim/mem_latency_stat.cc +++ b/src/gpgpu-sim/mem_latency_stat.cc @@ -79,46 +79,14 @@ #include <stdlib.h> #include <stdio.h> -bool gpgpu_memlatency_stat; - -unsigned max_mrq_latency; -unsigned max_dq_latency; -unsigned max_mf_latency; -unsigned max_icnt2mem_latency; -unsigned max_icnt2sh_latency; -unsigned mrq_lat_table[32]; -unsigned dq_lat_table[32]; -unsigned mf_lat_table[32]; -unsigned icnt2mem_lat_table[24]; -unsigned icnt2sh_lat_table[24]; -unsigned mf_lat_pw_table[32]; //table storing values of mf latency Per Window -unsigned mf_num_lat_pw; -unsigned mf_tot_lat_pw; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window -unsigned long long int mf_total_lat; -unsigned long long int ** mf_total_lat_table; //mf latency sums[dram chip id][bank id] -unsigned ** mf_max_lat_table; //mf latency sums[dram chip id][bank id] -unsigned num_mfs; -unsigned int ***bankwrites; //bankwrites[shader id][dram chip id][bank id] -unsigned int ***bankreads; //bankreads[shader id][dram chip id][bank id] -unsigned int **totalbankwrites; //bankwrites[dram chip id][bank id] -unsigned int **totalbankreads; //bankreads[dram chip id][bank id] -unsigned int **totalbankaccesses; //bankaccesses[dram chip id][bank id] -unsigned int *requests_by_warp; -unsigned int *num_MCBs_accessed; //tracks how many memory controllers are accessed whenever any thread in a warp misses in cache -unsigned int *position_of_mrq_chosen; //position of mrq in m_queue chosen -unsigned *mf_num_lat_pw_perwarp; -unsigned *mf_tot_lat_pw_perwarp; //total latency summed up per window per warp. divide by mf_num_lat_pw_perwarp to obtain average latency Per Window -unsigned long long int *mf_total_lat_perwarp; -unsigned *num_mfs_perwarp; -unsigned *acc_mrq_length; - -unsigned ***mem_access_type_stats; // dram access type classification - - -void memlatstat_init( ) +memory_stats_t::memory_stats_t( unsigned n_mem, unsigned n_shader, struct shader_core_config *shader_config, struct memory_config *mem_config ) { unsigned i,j; + m_n_shader=n_shader; + m_n_mem=n_mem; + m_memory_config=mem_config; + max_mrq_latency = 0; max_dq_latency = 0; max_mf_latency = 0; @@ -131,72 +99,85 @@ void memlatstat_init( ) memset(icnt2sh_lat_table, 0, sizeof(unsigned)*24); memset(mf_lat_pw_table, 0, sizeof(unsigned)*32); mf_num_lat_pw = 0; - mf_num_lat_pw_perwarp = (unsigned *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int)); - mf_tot_lat_pw_perwarp = (unsigned *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int)); - mf_total_lat_perwarp = (unsigned long long int *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned long long int)); - num_mfs_perwarp = (unsigned *) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int)); - acc_mrq_length = (unsigned *) calloc(gpu_n_mem, sizeof(unsigned int)); + max_warps = n_shader * (shader_config->n_thread_per_shader / shader_config->warp_size+1); + mf_num_lat_pw_perwarp = (unsigned *) calloc(max_warps, sizeof(unsigned int)); + mf_tot_lat_pw_perwarp = (unsigned *) calloc(max_warps, sizeof(unsigned int)); + mf_total_lat_perwarp = (unsigned long long int *) calloc(max_warps, sizeof(unsigned long long int)); + num_mfs_perwarp = (unsigned *) calloc(max_warps, sizeof(unsigned int)); + acc_mrq_length = (unsigned *) calloc(n_mem, sizeof(unsigned int)); mf_tot_lat_pw = 0; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window mf_total_lat = 0; num_mfs = 0; printf("*** Initializing Memory Statistics ***\n"); - requests_by_warp = (unsigned int*) calloc((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1, sizeof(unsigned int)); - totalbankreads = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - totalbankwrites = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - totalbankaccesses = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - mf_total_lat_table = (unsigned long long int **) calloc(gpu_n_mem, sizeof(unsigned long long *)); - mf_max_lat_table = (unsigned **) calloc(gpu_n_mem, sizeof(unsigned *)); - bankreads = (unsigned int***) calloc(gpu_n_shader, sizeof(unsigned int**)); - bankwrites = (unsigned int***) calloc(gpu_n_shader, sizeof(unsigned int**)); - num_MCBs_accessed = (unsigned int*) calloc(gpu_n_mem*gpu_mem_n_bk, sizeof(unsigned int)); - if (gpgpu_dram_sched_queue_size) { - position_of_mrq_chosen = (unsigned int*) calloc(gpgpu_dram_sched_queue_size, sizeof(unsigned int)); + totalbankreads = (unsigned int**) calloc(n_mem, sizeof(unsigned int*)); + totalbankwrites = (unsigned int**) calloc(n_mem, sizeof(unsigned int*)); + totalbankaccesses = (unsigned int**) calloc(n_mem, sizeof(unsigned int*)); + mf_total_lat_table = (unsigned long long int **) calloc(n_mem, sizeof(unsigned long long *)); + mf_max_lat_table = (unsigned **) calloc(n_mem, sizeof(unsigned *)); + bankreads = (unsigned int***) calloc(n_shader, sizeof(unsigned int**)); + bankwrites = (unsigned int***) calloc(n_shader, sizeof(unsigned int**)); + num_MCBs_accessed = (unsigned int*) calloc(n_mem*mem_config->gpu_mem_n_bk, sizeof(unsigned int)); + if (mem_config->gpgpu_dram_sched_queue_size) { + position_of_mrq_chosen = (unsigned int*) calloc(mem_config->gpgpu_dram_sched_queue_size, sizeof(unsigned int)); } else position_of_mrq_chosen = (unsigned int*) calloc(1024, sizeof(unsigned int)); - for (i=0;i<gpu_n_shader ;i++ ) { - bankreads[i] = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - bankwrites[i] = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*)); - for (j=0;j<gpu_n_mem ;j++ ) { - bankreads[i][j] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - bankwrites[i][j] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); + for (i=0;i<n_shader ;i++ ) { + bankreads[i] = (unsigned int**) calloc(n_mem, sizeof(unsigned int*)); + bankwrites[i] = (unsigned int**) calloc(n_mem, sizeof(unsigned int*)); + for (j=0;j<n_mem ;j++ ) { + bankreads[i][j] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int)); + bankwrites[i][j] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int)); } } - for (i=0;i<gpu_n_mem ;i++ ) { - totalbankreads[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - totalbankwrites[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - totalbankaccesses[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int)); - mf_total_lat_table[i] = (unsigned long long int*) calloc(gpu_mem_n_bk, sizeof(unsigned long long int)); - mf_max_lat_table[i] = (unsigned *) calloc(gpu_mem_n_bk, sizeof(unsigned)); + for (i=0;i<n_mem ;i++ ) { + totalbankreads[i] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int)); + totalbankwrites[i] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int)); + totalbankaccesses[i] = (unsigned int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned int)); + mf_total_lat_table[i] = (unsigned long long int*) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned long long int)); + mf_max_lat_table[i] = (unsigned *) calloc(mem_config->gpu_mem_n_bk, sizeof(unsigned)); } mem_access_type_stats = (unsigned ***) malloc(NUM_MEM_ACCESS_TYPE * sizeof(unsigned **)); for (i = 0; i < NUM_MEM_ACCESS_TYPE; i++) { int j; - mem_access_type_stats[i] = (unsigned **) calloc(gpu_n_mem, sizeof(unsigned*)); - for (j=0; (unsigned) j< gpu_n_mem; j++) { - mem_access_type_stats[i][j] = (unsigned *) calloc((gpu_mem_n_bk+1), sizeof(unsigned*)); + mem_access_type_stats[i] = (unsigned **) calloc(n_mem, sizeof(unsigned*)); + for (j=0; (unsigned) j< n_mem; j++) { + mem_access_type_stats[i][j] = (unsigned *) calloc((mem_config->gpu_mem_n_bk+1), sizeof(unsigned*)); } } + + L2_write_miss=0; + L2_write_hit=0; + L2_read_hit=0; + L2_read_miss=0; + L2_cbtoL2length = (unsigned int*) calloc(n_mem, sizeof(unsigned int)); + L2_cbtoL2writelength = (unsigned int*) calloc(n_mem, sizeof(unsigned int)); + L2_L2tocblength = (unsigned int*) calloc(n_mem, sizeof(unsigned int)); + L2_dramtoL2length = (unsigned int*) calloc(n_mem, sizeof(unsigned int)); + L2_dramtoL2writelength = (unsigned int*) calloc(n_mem, sizeof(unsigned int)); + L2_L2todramlength = (unsigned int*) calloc(n_mem, sizeof(unsigned int)); } -void memlatstat_start(mem_fetch_t *mf) +void memory_stats_t::memlatstat_start(mem_fetch *mf) { mf->timestamp = gpu_sim_cycle + gpu_tot_sim_cycle; mf->timestamp2 = 0; } // recorder the total latency -unsigned memlatstat_done(mem_fetch_t *mf) +unsigned memory_stats_t::memlatstat_done(mem_fetch *mf, unsigned n_warp_per_shader ) { unsigned mf_latency; - unsigned wid = mf->sid*gpu_n_warp_per_shader + mf->wid; + unsigned wid = mf->sid*n_warp_per_shader + mf->wid; + assert(wid<max_warps); mf_latency = (gpu_sim_cycle+gpu_tot_sim_cycle) - mf->timestamp; mf_num_lat_pw++; mf_num_lat_pw_perwarp[wid]++; mf_tot_lat_pw_perwarp[wid] += mf_latency; mf_tot_lat_pw += mf_latency; - check_time_vector_update(mf->mshr->insts[0].uid,MR_2SH_FQ_POP,mf_latency, mf->type ) ; + if( mf->mshr && mf->mshr->has_inst() ) + check_time_vector_update(mf->mshr->get_insts_uid(),MR_2SH_FQ_POP,mf_latency,mf->type); mf_lat_table[LOGB2(mf_latency)]++; shader_mem_lat_log(mf->sid, mf_latency); mf_total_lat_table[mf->chip][mf->bank] += mf_latency; @@ -205,15 +186,15 @@ unsigned memlatstat_done(mem_fetch_t *mf) return mf_latency; } -void memlatstat_icnt2sh_push(mem_fetch_t *mf) +void memory_stats_t::memlatstat_icnt2sh_push(mem_fetch *mf) { mf->timestamp2 = gpu_sim_cycle+gpu_tot_sim_cycle; } -void memlatstat_read_done(mem_fetch_t *mf) +void memory_stats_t::memlatstat_read_done(mem_fetch *mf, unsigned n_warp_per_shader) { - if (gpgpu_memlatency_stat) { - unsigned mf_latency = memlatstat_done(mf); + if (m_memory_config->gpgpu_memlatency_stat) { + unsigned mf_latency = memlatstat_done(mf,n_warp_per_shader); if (mf_latency > mf_max_lat_table[mf->chip][mf->bank]) { mf_max_lat_table[mf->chip][mf->bank] = mf_latency; @@ -227,13 +208,13 @@ void memlatstat_read_done(mem_fetch_t *mf) } } -void memlatstat_dram_access(mem_fetch_t *mf, unsigned dram_id, unsigned bank) +void memory_stats_t::memlatstat_dram_access(mem_fetch *mf) { - assert(dram_id < gpu_n_mem); - assert(bank < gpu_mem_n_bk); - if (gpgpu_memlatency_stat) { - if (mf->write) { - if ( (unsigned) mf->sid < gpu_n_shader ) { //do not count L2_writebacks here + unsigned dram_id = mf->chip; + unsigned bank = mf->bank; + if (m_memory_config->gpgpu_memlatency_stat) { + if (mf->m_write) { + if ( (unsigned) mf->sid < m_n_shader ) { //do not count L2_writebacks here bankwrites[mf->sid][dram_id][bank]++; shader_mem_acc_log( mf->sid, dram_id, bank, 'w'); } @@ -243,18 +224,16 @@ void memlatstat_dram_access(mem_fetch_t *mf, unsigned dram_id, unsigned bank) shader_mem_acc_log( mf->sid, dram_id, bank, 'r'); totalbankreads[dram_id][bank]++; } - if (mf->pc != (unsigned) -1) { ptx_file_line_stats_add_dram_traffic(mf->pc, 1); } - mem_access_type_stats[mf->mem_acc][dram_id][bank]++; } } -void memlatstat_icnt2mem_pop(mem_fetch_t *mf) +void memory_stats_t::memlatstat_icnt2mem_pop(mem_fetch *mf) { - if (gpgpu_memlatency_stat) { + if (m_memory_config->gpgpu_memlatency_stat) { unsigned icnt2mem_latency; icnt2mem_latency = (gpu_tot_sim_cycle+gpu_sim_cycle) - mf->timestamp; icnt2mem_lat_table[LOGB2(icnt2mem_latency)]++; @@ -263,10 +242,10 @@ void memlatstat_icnt2mem_pop(mem_fetch_t *mf) } } -void memlatstat_lat_pw( ) +void memory_stats_t::memlatstat_lat_pw( unsigned n_shader, unsigned n_thread_per_shader, unsigned warp_size ) { unsigned i; - if (mf_num_lat_pw && gpgpu_memlatency_stat) { + if (mf_num_lat_pw && m_memory_config->gpgpu_memlatency_stat) { assert(mf_tot_lat_pw); mf_total_lat = mf_tot_lat_pw; num_mfs = mf_num_lat_pw; @@ -274,12 +253,12 @@ void memlatstat_lat_pw( ) mf_tot_lat_pw = 0; mf_num_lat_pw = 0; } - for (i=0;i < ((gpu_n_shader * gpu_n_thread_per_shader / warp_size)+1); i++) { - if (mf_num_lat_pw_perwarp[i] && gpgpu_memlatency_stat) { + for (i=0;i < ((n_shader * n_thread_per_shader / warp_size)+1); i++) { + assert(i<max_warps); + if (mf_num_lat_pw_perwarp[i] && m_memory_config->gpgpu_memlatency_stat) { assert(mf_tot_lat_pw_perwarp[i]); mf_total_lat_perwarp[i] += mf_tot_lat_pw_perwarp[i]; num_mfs_perwarp[i] += mf_num_lat_pw_perwarp[i]; - //mf_lat_pw_table[LOGB2(mf_tot_lat_pw/mf_num_lat_pw)]++; mf_tot_lat_pw_perwarp[i] = 0; mf_num_lat_pw_perwarp[i] = 0; } @@ -287,12 +266,12 @@ void memlatstat_lat_pw( ) } -void memlatstat_print( ) +void memory_stats_t::memlatstat_print( unsigned n_mem, unsigned gpu_mem_n_bk ) { unsigned i,j,k,l,m; unsigned max_bank_accesses, min_bank_accesses, max_chip_accesses, min_chip_accesses; - if (gpgpu_memlatency_stat) { + if (m_memory_config->gpgpu_memlatency_stat) { printf("maxmrqlatency = %d \n", max_mrq_latency); printf("maxdqlatency = %d \n", max_dq_latency); printf("maxmflatency = %d \n", max_mf_latency); @@ -334,7 +313,7 @@ void memlatstat_print( ) /*MAXIMUM CONCURRENT ACCESSES TO SAME ROW*/ printf("maximum concurrent accesses to same row:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { printf("%9d ",max_conc_access2samerow[i][j]); @@ -344,7 +323,7 @@ void memlatstat_print( ) /*MAXIMUM SERVICE TIME TO SAME ROW*/ printf("maximum service time to same row:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { printf("%9d ",max_servicetime2samerow[i][j]); @@ -356,7 +335,7 @@ void memlatstat_print( ) int total_row_accesses = 0; int total_num_activates = 0; printf("average row accesses per activate:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { total_row_accesses += row_access[i][j]; @@ -375,7 +354,7 @@ void memlatstat_print( ) min_bank_accesses = 0xFFFFFFFF; min_chip_accesses = 0xFFFFFFFF; printf("number of total memory accesses made:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { l = totalbankaccesses[i][j]; @@ -413,7 +392,7 @@ void memlatstat_print( ) min_bank_accesses = 0xFFFFFFFF; min_chip_accesses = 0xFFFFFFFF; printf("number of total read accesses:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { l = totalbankreads[i][j]; @@ -451,7 +430,7 @@ void memlatstat_print( ) min_bank_accesses = 0xFFFFFFFF; min_chip_accesses = 0xFFFFFFFF; printf("number of total write accesses:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { l = totalbankwrites[i][j]; @@ -483,7 +462,7 @@ void memlatstat_print( ) /*AVERAGE MF LATENCY PER BANK*/ printf("average mf latency per bank:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { k = totalbankwrites[i][j] + totalbankreads[i][j]; @@ -497,7 +476,7 @@ void memlatstat_print( ) /*MAXIMUM MF LATENCY PER BANK*/ printf("maximum mf latency per bank:\n"); - for (i=0;i<gpu_n_mem ;i++ ) { + for (i=0;i<n_mem ;i++ ) { printf("dram[%d]: ", i); for (j=0;j<4 ;j++ ) { printf("%10d", mf_max_lat_table[i][j]); @@ -506,11 +485,11 @@ void memlatstat_print( ) } } - if (gpgpu_memlatency_stat & GPU_MEMLATSTAT_MC) { + if (m_memory_config->gpgpu_memlatency_stat & GPU_MEMLATSTAT_MC) { printf("\nNumber of Memory Banks Accessed per Memory Operation per Warp (from 0):\n"); unsigned long long accum_MCBs_accessed = 0; unsigned long long tot_mem_ops_per_warp = 0; - for (i=0;i<= gpu_n_mem*gpu_mem_n_bk ; i++ ) { + for (i=0;i<= n_mem*gpu_mem_n_bk ; i++ ) { accum_MCBs_accessed += i*num_MCBs_accessed[i]; tot_mem_ops_per_warp += num_MCBs_accessed[i]; printf("%d\t", num_MCBs_accessed[i]); @@ -523,10 +502,10 @@ void memlatstat_print( ) printf("\nposition of mrq chosen\n"); - if (!gpgpu_dram_sched_queue_size) + if (!m_memory_config->gpgpu_dram_sched_queue_size) j = 1024; else - j = gpgpu_dram_sched_queue_size; + j = m_memory_config->gpgpu_dram_sched_queue_size; k=0;l=0; for (i=0;i< j; i++ ) { printf("%d\t", position_of_mrq_chosen[i]); diff --git a/src/gpgpu-sim/mem_latency_stat.h b/src/gpgpu-sim/mem_latency_stat.h index fd057c4..c228c6e 100644 --- a/src/gpgpu-sim/mem_latency_stat.h +++ b/src/gpgpu-sim/mem_latency_stat.h @@ -68,49 +68,79 @@ #ifndef MEM_LATENCY_STAT_H #define MEM_LATENCY_STAT_H -extern bool gpgpu_memlatency_stat; +#include <stdio.h> -extern unsigned max_mrq_latency; -extern unsigned max_dq_latency; -extern unsigned max_mf_latency; -extern unsigned max_icnt2mem_latency; -extern unsigned max_icnt2sh_latency; -extern unsigned mrq_lat_table[32]; -extern unsigned dq_lat_table[32]; -extern unsigned mf_lat_table[32]; -extern unsigned icnt2mem_lat_table[24]; -extern unsigned icnt2sh_lat_table[24]; -extern unsigned mf_lat_pw_table[32]; //table storing values of mf latency Per Window -extern unsigned mf_num_lat_pw; -extern unsigned mf_tot_lat_pw; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window -extern unsigned long long int mf_total_lat; -extern unsigned long long int ** mf_total_lat_table; //mf latency sums[dram chip id][bank id] -extern unsigned ** mf_max_lat_table; //mf latency sums[dram chip id][bank id] -extern unsigned num_mfs; -extern unsigned int ***bankwrites; //bankwrites[shader id][dram chip id][bank id] -extern unsigned int ***bankreads; //bankreads[shader id][dram chip id][bank id] -extern unsigned int **totalbankwrites; //bankwrites[dram chip id][bank id] -extern unsigned int **totalbankreads; //bankreads[dram chip id][bank id] -extern unsigned int **totalbankaccesses; //bankaccesses[dram chip id][bank id] -extern unsigned int *requests_by_warp; -extern unsigned int *num_MCBs_accessed; //tracks how many memory controllers are accessed whenever any thread in a warp misses in cache -extern unsigned int *position_of_mrq_chosen; //position of mrq in m_queue chosen -extern unsigned *mf_num_lat_pw_perwarp; -extern unsigned *mf_tot_lat_pw_perwarp; //total latency summed up per window per warp. divide by mf_num_lat_pw_perwarp to obtain average latency Per Window -extern unsigned long long int *mf_total_lat_perwarp; -extern unsigned *num_mfs_perwarp; -extern unsigned *acc_mrq_length; +class memory_stats_t { +public: + memory_stats_t( unsigned n_mem, + unsigned n_shader, + struct shader_core_config *shader_config, + struct memory_config *mem_config ); -extern unsigned ***mem_access_type_stats; // dram access type classification + void memlatstat_start( class mem_fetch *mf); + unsigned memlatstat_done( class mem_fetch *mf, unsigned n_warp_per_shader ); + void memlatstat_icnt2sh_push( class mem_fetch *mf); + void memlatstat_read_done( class mem_fetch *mf, unsigned n_warp_per_shader); + void memlatstat_dram_access( class mem_fetch *mf ); + void memlatstat_icnt2mem_pop( class mem_fetch *mf); + void memlatstat_lat_pw( unsigned n_shader, unsigned n_thread_per_shader, unsigned warp_size ); + void memlatstat_print(unsigned n_mem, unsigned gpu_mem_n_bk); -void memlatstat_init(); -void memlatstat_start(struct mem_fetch *mf); -unsigned memlatstat_done(struct mem_fetch *mf); -void memlatstat_icnt2sh_push(struct mem_fetch *mf); -void memlatstat_read_done(struct mem_fetch *mf); -void memlatstat_dram_access(struct mem_fetch *mf, unsigned dram_id, unsigned bank); -void memlatstat_icnt2mem_pop(struct mem_fetch *mf); -void memlatstat_lat_pw(); -void memlatstat_print(); + void L2c_print_stat(unsigned n_mem); + + void print( FILE *fp ); + + unsigned m_n_mem; + unsigned m_n_shader; + + const struct shader_core_config *m_shader_config; + const struct memory_config *m_memory_config; + + unsigned max_mrq_latency; + unsigned max_dq_latency; + unsigned max_mf_latency; + unsigned max_icnt2mem_latency; + unsigned max_icnt2sh_latency; + unsigned mrq_lat_table[32]; + unsigned dq_lat_table[32]; + unsigned mf_lat_table[32]; + unsigned icnt2mem_lat_table[24]; + unsigned icnt2sh_lat_table[24]; + unsigned mf_lat_pw_table[32]; //table storing values of mf latency Per Window + unsigned mf_num_lat_pw; + unsigned max_warps; + unsigned mf_tot_lat_pw; //total latency summed up per window. divide by mf_num_lat_pw to obtain average latency Per Window + unsigned long long int mf_total_lat; + unsigned long long int ** mf_total_lat_table; //mf latency sums[dram chip id][bank id] + unsigned ** mf_max_lat_table; //mf latency sums[dram chip id][bank id] + unsigned num_mfs; + unsigned int ***bankwrites; //bankwrites[shader id][dram chip id][bank id] + unsigned int ***bankreads; //bankreads[shader id][dram chip id][bank id] + unsigned int **totalbankwrites; //bankwrites[dram chip id][bank id] + unsigned int **totalbankreads; //bankreads[dram chip id][bank id] + unsigned int **totalbankaccesses; //bankaccesses[dram chip id][bank id] + unsigned int *num_MCBs_accessed; //tracks how many memory controllers are accessed whenever any thread in a warp misses in cache + unsigned int *position_of_mrq_chosen; //position of mrq in m_queue chosen + unsigned *mf_num_lat_pw_perwarp; + unsigned *mf_tot_lat_pw_perwarp; //total latency summed up per window per warp. divide by mf_num_lat_pw_perwarp to obtain average latency Per Window + unsigned long long int *mf_total_lat_perwarp; + unsigned *num_mfs_perwarp; + unsigned *acc_mrq_length; + + unsigned ***mem_access_type_stats; // dram access type classification + + + // stats + unsigned L2_write_miss; + unsigned L2_write_hit; + unsigned L2_read_hit; + unsigned L2_read_miss; + unsigned int *L2_cbtoL2length; + unsigned int *L2_cbtoL2writelength; + unsigned int *L2_L2tocblength; + unsigned int *L2_dramtoL2length; + unsigned int *L2_dramtoL2writelength; + unsigned int *L2_L2todramlength; +}; #endif /*MEM_LATENCY_STAT_H*/ diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc index 278ada4..711a6ab 100644 --- a/src/gpgpu-sim/scoreboard.cc +++ b/src/gpgpu-sim/scoreboard.cc @@ -11,16 +11,17 @@ //Constructor -Scoreboard::Scoreboard( int sid, int n_warps ) +Scoreboard::Scoreboard( unsigned sid, unsigned n_warps ) { - this->sid = sid; + m_sid = sid; //Initialize size of table reg_table.resize(n_warps); } // Print scoreboard contents -void Scoreboard::printContents() { - printf("scoreboard contents (sid=%d): \n", sid); +void Scoreboard::printContents() +{ + printf("scoreboard contents (sid=%d): \n", m_sid); for(unsigned i=0; i<reg_table.size(); i++) { if(reg_table[i].size() == 0 ) continue; printf(" wid = %d: ", i); @@ -33,9 +34,10 @@ void Scoreboard::printContents() { // Mark register as write-pending -void Scoreboard::reserveRegister(int wid, int regnum) { +void Scoreboard::reserveRegister(unsigned wid, unsigned regnum) +{ if( !(reg_table[wid].find(regnum) == reg_table[wid].end()) ){ - printf("Error: trying to reserve an already reserved register (sid=%d, wid=%d, regnum=%d).", sid, wid, regnum); + printf("Error: trying to reserve an already reserved register (sid=%d, wid=%d, regnum=%d).", m_sid, wid, regnum); assert(reg_table[wid].find(regnum) == reg_table[wid].end()); } @@ -44,20 +46,19 @@ void Scoreboard::reserveRegister(int wid, int regnum) { // Unmark register as write-pending -void Scoreboard::releaseRegister(int wid, int regnum) { +void Scoreboard::releaseRegister(unsigned wid, unsigned regnum) +{ if( !(reg_table[wid].find(regnum) != reg_table[wid].end()) ) { - printf("Error: trying to release an unreserved register (sid=%d, wid=%d, regnum=%d).", sid, wid, regnum); + printf("Error: trying to release an unreserved register (sid=%d, wid=%d, regnum=%d).", m_sid, wid, regnum); assert(reg_table[wid].find(regnum) != reg_table[wid].end()); } - reg_table[wid].erase(regnum); } // Reserve registers for an instruction -void Scoreboard::reserveRegisters(int wid, void* inst_void) { - inst_t *inst = (inst_t *) inst_void; - +void Scoreboard::reserveRegisters(unsigned wid, const class inst_t* inst) +{ // Reserve registers if(inst->out[0] > 0) reserveRegister(wid, inst->out[0]); if(inst->out[1] > 0) reserveRegister(wid, inst->out[1]); @@ -66,19 +67,22 @@ void Scoreboard::reserveRegisters(int wid, void* inst_void) { } // Release registers for an instruction -void Scoreboard::releaseRegisters(int wid, void *inst_void) { - inst_t *inst = (inst_t *) inst_void; - +void Scoreboard::releaseRegisters(unsigned wid, const class inst_t *inst) +{ if(inst->out[0] > 0) releaseRegister(wid, inst->out[0]); if(inst->out[1] > 0) releaseRegister(wid, inst->out[1]); if(inst->out[2] > 0) releaseRegister(wid, inst->out[2]); if(inst->out[3] > 0) releaseRegister(wid, inst->out[3]); } -// Checks to see if registers used by an instruction are reserved in the scoreboard -bool Scoreboard::checkCollision(int wid, void *inst_void) { - inst_t *inst = (inst_t *) inst_void; - +/** + * Checks to see if registers used by an instruction are reserved in the scoreboard + * + * @return + * true if WAW or RAW hazard (no WAR since in-order issue) + **/ +bool Scoreboard::checkCollision( unsigned wid, const class inst_t *inst ) +{ // Get list of all input and output registers std::set<int> inst_regs; @@ -94,32 +98,16 @@ bool Scoreboard::checkCollision(int wid, void *inst_void) { if(inst->ar1 > 0) inst_regs.insert(inst->ar1); if(inst->ar2 > 0) inst_regs.insert(inst->ar2); - /* - printf("Inst registers: "); - std::set<int>::iterator it; - for ( it=inst_regs.begin() ; it != inst_regs.end(); it++ ) - printf("%d ", *it); - printf("\n"); - */ - // Check for collision, get the intersection of reserved registers and instruction registers - //std::set<int> reg_intr; std::set<int>::iterator it2; for ( it2=inst_regs.begin() ; it2 != inst_regs.end(); it2++ ) if(reg_table[wid].find(*it2) != reg_table[wid].end()) { - //reg_intr.insert(*it2); return true; } - return false; +} - /* - printf("Intersection registers: "); - std::set<int>::iterator it3; - for ( it3=reg_intr.begin() ; it3 != reg_intr.end(); it3++ ) - printf("%d ", *it3); - printf("\n"); - */ - - +bool Scoreboard::pendingWrites(unsigned wid) const +{ + return !reg_table[wid].empty(); } diff --git a/src/gpgpu-sim/scoreboard.h b/src/gpgpu-sim/scoreboard.h index 4139948..6cec22c 100644 --- a/src/gpgpu-sim/scoreboard.h +++ b/src/gpgpu-sim/scoreboard.h @@ -14,29 +14,28 @@ #ifndef SCOREBOARD_H_ #define SCOREBOARD_H_ -typedef unsigned op_type; +#include "../abstract_hardware_model.h" -class Scoreboard -{ - private: - int sid; // Shader id - // Table to keep track of write-pending registers - // Indexed by warp id (wid) - std::vector< std::set<int> > reg_table; +class Scoreboard { +public: + Scoreboard( unsigned sid, unsigned n_warps ); - void reserveRegister(int wid, int regnum); - void releaseRegister(int wid, int regnum); + void printContents(); - public: - Scoreboard( int sid, int n_warps ); + void reserveRegisters(unsigned wid, const inst_t *inst); + void releaseRegisters(unsigned wid, const inst_t *inst); - void printContents(); + bool checkCollision(unsigned wid, const inst_t *inst); + bool pendingWrites(unsigned wid) const; +private: + void reserveRegister(unsigned wid, unsigned regnum); + void releaseRegister(unsigned wid, unsigned regnum); - void reserveRegisters(int wid, void *inst_void); - void releaseRegisters(int wid, void *inst_void); - - bool checkCollision(int wid, void *inst_void); + unsigned m_sid; + // keeps track of pending writes to registers + // indexed by warp id + std::vector< std::set<int> > reg_table; }; diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 5f465ed..1f2be5a 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -87,62 +87,8 @@ #define PRIORITIZE_MSHR_OVER_WB 1 #define MAX(a,b) (((a)>(b))?(a):(b)) -extern bool gpgpu_stall_on_use; -enum mem_stage_access_type { - C_MEM, - T_MEM, - S_MEM, - G_MEM_LD, - L_MEM_LD, - G_MEM_ST, - L_MEM_ST, - N_MEM_STAGE_ACCESS_TYPE -}; - -enum mem_stage_stall_type { - NO_RC_FAIL = 0, - BK_CONF, - MSHR_RC_FAIL, - ICNT_RC_FAIL, - COAL_STALL, - WB_ICNT_RC_FAIL, - WB_CACHE_RSRV_FAIL, - N_MEM_STAGE_STALL_TYPE -}; -unsigned int gpu_stall_shd_mem_breakdown[N_MEM_STAGE_ACCESS_TYPE][N_MEM_STAGE_STALL_TYPE] = { {0} }; -unsigned warp_size = 4; -int pipe_simd_width; -unsigned int *shader_cycle_distro; -unsigned int g_waiting_at_barrier = 0; -unsigned int gpgpu_shmem_size; -unsigned int gpgpu_shader_registers; -unsigned int gpgpu_shader_cta; -unsigned int gpgpu_n_load_insn = 0; -unsigned int gpgpu_n_store_insn = 0; -unsigned int gpgpu_n_shmem_insn = 0; -unsigned int gpgpu_n_tex_insn = 0; -unsigned int gpgpu_n_const_insn = 0; -unsigned int gpgpu_n_param_insn = 0; -unsigned int gpgpu_multi_unq_fetches = 0; -bool gpgpu_shmem_bkconflict; -unsigned int gpgpu_n_shmem_bkconflict = 0; -int gpgpu_n_shmem_bank = 16; -bool gpgpu_cache_bkconflict; -unsigned int gpgpu_n_cache_bkconflict = 0; -unsigned int gpgpu_n_cmem_portconflict = 0; -int gpgpu_n_cache_bank; -int gpgpu_warpdistro_shader; -int gpgpu_interwarp_mshr_merge; -int gpgpu_n_intrawarp_mshr_merge = 0; -int gpgpu_n_partial_writes = 0; -int gpgpu_shmem_port_per_bank; -int gpgpu_cache_port_per_bank; -int gpgpu_const_port_per_bank; -int gpgpu_shmem_pipe_speedup; -unsigned int gpu_max_cta_per_shader = 8; -unsigned int gpu_padded_cta_size = 32; -int gpgpu_local_mem_map; +unsigned mem_access_t::next_access_uid = 0; ///////////////////////////////////////////////////////////////////////////// /*-------------------------------------------------------------------------*/ @@ -150,312 +96,276 @@ int gpgpu_local_mem_map; static const char* MSHR_Status_str[] = { "INITIALIZED", + "INVALID", "IN_ICNT2MEM", - "IN_ICNTOL2QUEUE", + "IN_CBTOL2QUEUE", "IN_L2TODRAMQUEUE", "IN_DRAM_REQ_QUEUE", + "IN_DRAMRETURN_Q", "IN_DRAMTOL2QUEUE", - "IN_L2TOICNTQUEUE_HIT", - "IN_L2TOICNTQUEUE_MISS", + "IN_L2TOCBQUEUE_HIT", + "IN_L2TOCBQUEUE_MISS", "IN_ICNT2SHADER", "FETCHED", }; -// a helper function that deduce if a mshr contains an atomic operation -bool isatomic(mshr_entry_t *mshr) +void mshr_lookup::insert(mshr_entry* mshr) { - return (mshr->insts[0].callback.function != NULL); + using namespace std; + new_addr_type tag_addr = mshr->get_addr(); + m_lut.insert(make_pair(tag_addr, mshr)); } -#include <map> -#include <utility> -#include <algorithm> -// a class that speeds up mshr lookup with a C++ multimap -class mshr_lookup { -private: - typedef std::multimap<unsigned long long int, mshr_entry*> mshr_lut_t; - mshr_lut_t m_lut; // multiple mshr entries can have the same tag -private: - void insert(mshr_entry* mshr) - { - using namespace std; - unsigned long long int tag_addr = mshr->addr; - m_lut.insert(make_pair(tag_addr, mshr)); +mshr_entry* mshr_lookup::lookup( new_addr_type addr ) const +{ + std::pair<mshr_lut_t::const_iterator, mshr_lut_t::const_iterator> i_range = m_lut.equal_range(addr); + if (i_range.first == i_range.second) { + return NULL; + } else { + mshr_lut_t::const_iterator i_lut = i_range.first; + return i_lut->second->get_last_merged(); } +} - mshr_entry* lookup(unsigned long long int addr) const - { - using namespace std; - // mshr_lut_t::const_iterator i_lut = m_lut.find(tag_addr); - pair<mshr_lut_t::const_iterator, mshr_lut_t::const_iterator> i_range = m_lut.equal_range(addr); - if (i_range.first == i_range.second) { - return NULL; - } else { - mshr_lut_t::const_iterator i_lut = i_range.first; - mshr_entry* mshr_hit = i_lut->second; - //follow match to end of merge chain: - //this won't really work for different sized requests, ie can't merge a 64b request to a 32b - while (mshr_hit->merged_requests) { - mshr_hit = mshr_hit->merged_requests; - } - return mshr_hit; - } - } - - void remove(mshr_entry* mshr) - { - using namespace std; - std::pair<mshr_lut_t::iterator, mshr_lut_t::iterator> i_range = m_lut.equal_range(mshr->addr); +void mshr_lookup::remove(mshr_entry* mshr) +{ + using namespace std; + std::pair<mshr_lut_t::iterator, mshr_lut_t::iterator> i_range = m_lut.equal_range(mshr->get_addr()); - assert(i_range.first != i_range.second); + assert(i_range.first != i_range.second); - for (mshr_lut_t::iterator i_lut = i_range.first; i_lut != i_range.second; ++i_lut) { - if (i_lut->second == mshr) { - m_lut.erase(i_lut); - break; - } - } - } -public: - //checks if we should do mshr merging for this mshr - bool can_merge(mshr_entry_t * mshr) - { - if (mshr->iswrite) return false; // can't merge a write - if (isatomic(mshr)) return false; // can't merge a atomic operation - bool interwarp_mshr_merge = gpgpu_interwarp_mshr_merge & GLOBAL_MSHR_MERGE; - if (mshr->istexture) { - interwarp_mshr_merge = gpgpu_interwarp_mshr_merge & TEX_MSHR_MERGE; - } else if (mshr->isconst) { - interwarp_mshr_merge = gpgpu_interwarp_mshr_merge & CONST_MSHR_MERGE; + for (mshr_lut_t::iterator i_lut = i_range.first; i_lut != i_range.second; ++i_lut) { + if (i_lut->second == mshr) { + m_lut.erase(i_lut); + break; } - return interwarp_mshr_merge; } +} - void mshr_fast_lookup_insert(mshr_entry* mshr) - { - if (!can_merge(mshr)) return; - insert(mshr); - } +//checks if we should do mshr merging for this mshr +bool mshr_lookup::can_merge(mshr_entry * mshr) +{ + if (mshr->iswrite()) + return false; // can't merge a write + if (mshr->isatomic()) + return false; // can't merge a atomic operation + bool interwarp_mshr_merge = m_shader_config->gpgpu_interwarp_mshr_merge & GLOBAL_MSHR_MERGE; + if (mshr->isinst()) + interwarp_mshr_merge=true; + else if (mshr->istexture()) + interwarp_mshr_merge = m_shader_config->gpgpu_interwarp_mshr_merge & TEX_MSHR_MERGE; + else if (mshr->isconst()) + interwarp_mshr_merge = m_shader_config->gpgpu_interwarp_mshr_merge & CONST_MSHR_MERGE; + return interwarp_mshr_merge; +} + +void mshr_lookup::mshr_fast_lookup_insert(mshr_entry* mshr) +{ + if (!can_merge(mshr)) + return; + insert(mshr); +} - void mshr_fast_lookup_remove(mshr_entry* mshr) - { - if (!can_merge(mshr)) return; - remove(mshr); - } +void mshr_lookup::mshr_fast_lookup_remove(mshr_entry* mshr) +{ + if (!can_merge(mshr)) + return; + remove(mshr); +} - mshr_entry* shader_get_mergeable_mshr(mshr_entry_t* mshr) - { - if (!can_merge(mshr)) return NULL; - return lookup(mshr->addr); - } -}; +mshr_entry* mshr_lookup::shader_get_mergeable_mshr(mshr_entry* mshr) +{ + if (!can_merge(mshr)) return NULL; + return lookup(mshr->get_addr()); +} -class mem_access_t; -int is_tex ( int space ); -int is_const ( int space ); -int is_local ( int space ); -#include <iostream> -class mshr_shader_unit{ -public: - mshr_shader_unit(unsigned max_mshr): m_max_mshr(max_mshr), m_max_mshr_used(0){ - m_mshrs.resize(max_mshr); - for (std::vector<mshr_entry_t>::iterator i = m_mshrs.begin(); i != m_mshrs.end(); i++) m_free_list.push_back(i); - } - bool has_mshr(unsigned num){return (num <= m_free_list.size());} - unsigned mshr_used(){ return m_max_mshr - m_free_list.size();} - mshr_entry_t* add_mshr(mem_access_t &access, inst_t* warp); +mshr_shader_unit::mshr_shader_unit( const shader_core_config *config ): m_max_mshr_used(0), m_mshr_lookup(config) +{ + m_shader_config=config; + m_mshrs.resize(config->n_mshr_per_shader); + unsigned n=0; + for (std::vector<mshr_entry>::iterator i = m_mshrs.begin(); i != m_mshrs.end(); i++) { + mshr_entry &mshr = *i; + mshr.set_id(n++); + m_free_list.push_back(&mshr); + } +} - //return queue access; (includes texture pipeline return) - mshr_entry_t* return_head(){ - if (has_return()) - return &(*(choose_return_queue().front())); - else - return NULL; - } - //return queue pop; (includes texture pipeline return) - void pop_return_head() { - free_mshr(return_head()->this_mshr); - choose_return_queue().pop_front(); - } +mshr_entry* mshr_shader_unit::return_head() +{ + if (has_return()) + return &(*choose_return_queue().front()); + else + return NULL; +} - static void mshr_update_status(mshr_entry *mshr, enum mshr_status new_status ); - void mshr_return_from_mem(mshr_entry *mshr); - void check_mshr(mshr_entry *mshr){ - assert(find(m_free_list.begin(),m_free_list.end(),mshr->this_mshr)==m_free_list.end()); - assert(mshr->insts.size()); - } - unsigned get_max_mshr_used(){return m_max_mshr_used;} - void print(FILE* fp, shader_core_ctx_t* shader); -private: - typedef std::vector<mshr_entry_t> mshr_storage_type;//list might be less complicated, but slower? - mshr_storage_type m_mshrs; - std::deque< mshr_storage_type::iterator > m_free_list; - std::deque< mshr_storage_type::iterator > m_mshr_return_queue; - std::deque< mshr_storage_type::iterator > m_texture_mshr_pipeline; - unsigned m_max_mshr; - unsigned m_max_mshr_used; - mshr_lookup m_mshr_lookup; +void mshr_shader_unit::pop_return_head() +{ + free_mshr(return_head()); + choose_return_queue().pop_front(); +} - mshr_entry_t *alloc_free_mshr(bool istexture){ - assert(!m_free_list.empty()); - std::vector<mshr_entry_t>::iterator i = m_free_list.back(); - m_free_list.pop_back(); - i->this_mshr = i; - if (istexture) { - //put in texture pipeline - m_texture_mshr_pipeline.push_back(i); - } - if (mshr_used() > m_max_mshr_used) m_max_mshr_used = mshr_used(); - return &(*i); - } - void free_mshr(std::vector<mshr_entry_t>::iterator &i){ - //clean up up for next time, since not reallocating memory. - m_mshr_lookup.mshr_fast_lookup_remove(&(*i)); //need to remove before clearing insts, as they are accessed - i->insts.clear(); //add expects this to be clear - m_free_list.push_back(i); - } - bool has_return() { return (not m_mshr_return_queue.empty()) or ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched());} - std::deque< std::vector<mshr_entry_t>::iterator > & choose_return_queue() { - //prioritize a ready texture over a global/const... - if ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched()) return m_texture_mshr_pipeline; - assert(!m_mshr_return_queue.empty()); - return m_mshr_return_queue; - } -}; +mshr_entry *mshr_shader_unit::alloc_free_mshr(bool istexture) +{ + assert(!m_free_list.empty()); + mshr_entry *mshr = m_free_list.back(); + m_free_list.pop_back(); + if (istexture) + m_texture_mshr_pipeline.push_back(mshr); + if (mshr_used() > m_max_mshr_used) + m_max_mshr_used = mshr_used(); + return mshr; +} +void mshr_shader_unit::free_mshr( mshr_entry *mshr ) +{ + //clean up up for next time, since not reallocating memory. + m_mshr_lookup.mshr_fast_lookup_remove(mshr); + mshr->clear(); + m_free_list.push_back(mshr); +} +unsigned mshr_shader_unit::mshr_used() const +{ + return m_shader_config->n_mshr_per_shader - m_free_list.size(); +} -void mshr_shader_unit::mshr_update_status(mshr_entry *mshr, enum mshr_status new_status ) { - mshr->status = new_status; -#if DEBUGL1MISS - printf("cycle %d Addr %x %d \n",gpu_sim_cycle,CACHE_TAG_OF_64(mshr->addr),new_status); -#endif - mshr_entry * merged_req = mshr->merged_requests; - while (merged_req) { - merged_req->status = new_status; - merged_req = merged_req->merged_requests; - } +std::deque<mshr_entry*> &mshr_shader_unit::choose_return_queue() +{ + // prioritize a ready texture over a global/const... + if ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched()) + return m_texture_mshr_pipeline; + assert(!m_mshr_return_queue.empty()); + return m_mshr_return_queue; } -inline void mshr_shader_unit::mshr_return_from_mem(mshr_entry *mshr){ - mshr_update_status(mshr, FETCHED); - if (not mshr->istexture) { +void mshr_shader_unit::mshr_return_from_mem(mshr_entry *mshr) +{ + mshr->set_status( FETCHED ); + if ( not mshr->istexture() ) { //place in return queue - m_mshr_return_queue.push_back(mshr->this_mshr); - //place all merged requests in return queue - mshr_entry * merged_req = mshr->merged_requests; - while (merged_req) { - m_mshr_return_queue.push_back(merged_req->this_mshr); - merged_req = merged_req->merged_requests; - } + mshr->add_to_queue( m_mshr_return_queue ); } } -void mshr_return_from_mem(shader_core_ctx_t * shader, mshr_entry_t* mshr){ - shader->mshr_unit->mshr_return_from_mem(mshr); +void shader_core_ctx::mshr_print(FILE* fp, unsigned mask) +{ + m_mshr_unit->print(fp, this, mask); } -unsigned get_max_mshr_used(shader_core_ctx_t * shader){ - return shader->mshr_unit->get_max_mshr_used(); +void mshr_shader_unit::print(FILE* fp, shader_core_ctx* shader, unsigned mask) +{ + unsigned n=0; + unsigned num_outstanding = 0; + for (mshr_storage_type::iterator it = m_mshrs.begin(); it != m_mshrs.end(); it++,n++) { + mshr_entry *mshr = &(*it); + if (find(m_free_list.begin(),m_free_list.end(), mshr) == m_free_list.end()) { + num_outstanding++; + mshr->print(fp,mask); + } + } + fprintf(fp,"\nTotal outstanding memory requests = %u\n", num_outstanding ); } +unsigned char shader_core_ctx::fq_push(unsigned long long int addr, + int bsize, + unsigned char write, + partial_write_mask_t partial_write_mask, + int wid, + mshr_entry* mshr, + int cache_hits_waiting, + enum mem_access_type mem_acc, + address_type pc) +{ + assert(write || (partial_write_mask == NO_PARTIAL_WRITE)); + int nbytes_L2 = m_gpu->get_L2_linesize(); + mem_fetch *mf = new mem_fetch(addr, + bsize, + nbytes_L2, + m_sid, + m_tpc, + wid, + cache_hits_waiting, + mshr, + write, + partial_write_mask, + mem_acc, + write?WT_REQ:RD_REQ, + pc); + if (mshr) mshr->set_mf(mf); + + // stats + if (write) made_write_mfs++; + else made_read_mfs++; + switch (mem_acc) { + case CONST_ACC_R: m_stats->gpgpu_n_mem_const++; break; + case TEXTURE_ACC_R: m_stats->gpgpu_n_mem_texture++; break; + case GLOBAL_ACC_R: m_stats->gpgpu_n_mem_read_global++; break; + case GLOBAL_ACC_W: m_stats->gpgpu_n_mem_write_global++; break; + case LOCAL_ACC_R: m_stats->gpgpu_n_mem_read_local++; break; + case LOCAL_ACC_W: m_stats->gpgpu_n_mem_write_local++; break; + case INST_ACC_R: m_stats->gpgpu_n_mem_read_inst++; break; + default: assert(0); + } -void mshr_print(FILE* fp, shader_core_ctx_t *shader) { - shader->mshr_unit->print(fp, shader); + return(m_gpu->issue_mf_from_fq(mf)); } -void mshr_shader_unit::print(FILE* fp, shader_core_ctx_t* shader){ - for (mshr_storage_type::iterator it = m_mshrs.begin(); it != m_mshrs.end(); it++) { - //valid if not in free list; - if (find(m_free_list.begin(),m_free_list.end(), it) == m_free_list.end()) { - mshr_entry *mshr = &(*it); - fprintf(fp, "MSHR(%d): %s Addr:0x%llx Fetched:%d Merged:%d Status:%s\n", - shader->sid, - (mshr->iswrite)? "=>" : "<=", - mshr->addr, mshr->fetched(), - (mshr->merged_requests != NULL or mshr->merged_on_other_reqest), MSHR_Status_str[mshr->status]); - for (unsigned i = 0; i < mshr->insts.size(); i++) { - fprintf(fp,"\tthread: UID:%d HW:%d ReqAddr:0x%llx\n", mshr->insts[i].uid, mshr->insts[i].hw_thread_id, mshr->insts[i].memreqaddr); - } - } - } +inst_t *shader_core_ctx::first_valid_thread( inst_t *warp ) +{ + for(unsigned t=0; t < m_config->warp_size; t++ ) + if( warp[t].hw_thread_id != -1 ) + return warp+t; + return NULL; } -void mshr_update_status(mshr_entry* mshr, enum mshr_status new_status) { - mshr_entry *merged_req; - mshr->status = new_status; -#if DEBUGL1MISS - printf("cycle %d Addr %x %d \n",gpu_sim_cycle,CACHE_TAG_OF_64(mshr->addr),new_status); -#endif - merged_req = mshr->merged_requests; - while (merged_req) { - merged_req->status = new_status; - merged_req = merged_req->merged_requests; - } +inst_t *shader_core_ctx::first_valid_thread( unsigned stage ) +{ + return first_valid_thread(m_pipeline_reg[stage]); } -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// -/*-------------------------------------------------------------------------*/ +void shader_core_ctx::move_warp( inst_t *&dst, inst_t *&src ) +{ -inst_t create_nop_inst() // just because C++ does not have designated initializer list.... + assert( pipeline_regster_empty(dst) ); + inst_t* temp = dst; + dst = src; + src = temp; + for( unsigned t=0; t < m_config->warp_size; t++) + src[t] = inst_t(); +} + +void shader_core_ctx::clear_stage( inst_t *warp ) { - inst_t nop_inst; - nop_inst.pc = 0; - nop_inst.op=NO_OP; - memset(nop_inst.out, 0, sizeof(nop_inst.out)); - memset(nop_inst.in, 0, sizeof(nop_inst.in)); - nop_inst.is_vectorin=0; - nop_inst.is_vectorout=0; - nop_inst.memreqaddr=0; - nop_inst.reg_bank_access_pending=0; - nop_inst.reg_bank_conflict_stall_checked=0, - nop_inst.hw_thread_id=-1; - nop_inst.wlane=-1; - nop_inst.uid = (unsigned)-1; - nop_inst.priority = (unsigned)-1; - nop_inst.ptx_thd_info = NULL; - nop_inst.warp_active_mask = 0; - nop_inst.ts_cycle = 0; - nop_inst.id_cycle = 0; - nop_inst.ex_cycle = 0; - nop_inst.mm_cycle = 0; - nop_inst.cache_miss = false; - nop_inst.space = memory_space_t(); - nop_inst.cycles = 0; - return nop_inst; + for( unsigned t=0; t < m_config->warp_size; t++) + warp[t] = inst_t(); } -static inst_t nop_inst = create_nop_inst(); +bool shader_core_ctx::pipeline_regster_empty( inst_t *reg ) +{ + return first_valid_thread(reg) == NULL; +} -inst_t *first_valid_thread( inst_t *warp ) +void shader_core_ctx::L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const { - for(unsigned t=0; t < ::warp_size; t++ ) - if( warp[t].hw_thread_id != -1 ) - return warp+t; - return NULL; + shd_cache_print(m_L1D,fp,total_accesses,total_misses); } -void move_warp( inst_t *dst, inst_t *src ) +void shader_core_ctx::L1texcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const { - memcpy(dst,src,::warp_size * sizeof(inst_t)); - for( unsigned t=0; t < ::warp_size; t++) - src[t] = nop_inst; + shd_cache_print(m_L1T,fp,total_accesses,total_misses); } -bool pipeline_regster_empty( inst_t *reg ) +void shader_core_ctx::L1constcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const { - return first_valid_thread(reg) == NULL; + shd_cache_print(m_L1C,fp,total_accesses,total_misses); } -std::list<unsigned> get_regs_written( inst_t *warp ) +std::list<unsigned> shader_core_ctx::get_regs_written( const inst_t &fvt ) const { std::list<unsigned> result; - inst_t *fvi = first_valid_thread(warp); - if( fvi == NULL ) - return result; for( unsigned op=0; op < 4; op++ ) { - int reg_num = fvi->arch_reg[op]; // this math needs to match that used in function_info::ptx_decode_inst + int reg_num = fvt.arch_reg[op]; // this math needs to match that used in function_info::ptx_decode_inst if( reg_num >= 0 ) // valid register result.push_back(reg_num); } @@ -471,694 +381,396 @@ int log2i(int n) { return lg; } -shader_core_ctx_t* shader_create( const char *name, int sid, - unsigned int n_threads, - unsigned int n_mshr, - fq_push_t fq_push, - fq_has_buffer_t fq_has_buffer, - unsigned int model ) -{ - shader_core_ctx_t *sc; - sc = (shader_core_ctx_t*)calloc(sizeof(shader_core_ctx_t),1); - sc = new (sc) shader_core_ctx(name,sid,n_threads,n_mshr,fq_push,fq_has_buffer,model, - gpu_n_warp_per_shader,gpgpu_shader_cta); - return sc; -} - -shader_core_ctx::shader_core_ctx( const char *name, int sid, - unsigned int n_threads, - unsigned int n_mshr, - fq_push_t fq_push, - fq_has_buffer_t fq_has_buffer, - unsigned model, - unsigned max_warps_per_cta, unsigned max_cta_per_core ) - : m_barriers( max_warps_per_cta, max_cta_per_core ) +shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, + const char *name, + unsigned shader_id, + unsigned tpc_id, + const struct shader_core_config *config, + struct shader_core_stats *stats ) + : m_barriers( config->max_warps_per_shader, config->max_cta_per_core ) { - shader_core_ctx *sc = this; - assert( !((model == DWF) && gpgpu_operand_collector) ); - - int i; - unsigned int shd_n_set; - unsigned int shd_linesize; - unsigned int shd_n_assoc; - unsigned char shd_policy; - - unsigned int l1tex_cache_n_set; //L1 texture cache parameters - unsigned int l1tex_cache_linesize; - unsigned int l1tex_cache_n_assoc; - unsigned char l1tex_cache_policy; + m_gpu = gpu; + m_config = config; + m_stats = stats; + unsigned warp_size=config->warp_size; + assert( !((config->model == DWF) && m_config->gpgpu_operand_collector) ); - unsigned int l1const_cache_n_set; //L1 constant cache parameters - unsigned int l1const_cache_linesize; - unsigned int l1const_cache_n_assoc; - unsigned char l1const_cache_policy; - - if ( gpgpu_cuda_sim ) { - unsigned cta_size = ptx_sim_cta_size(); - if ( cta_size > n_threads ) { - printf("Execution error: Shader kernel CTA (block) size is too large for microarch config.\n"); - printf(" This can cause problems with applications that use __syncthreads.\n"); - printf(" CTA size (x*y*z) = %u, n_threads = %u\n", cta_size, n_threads ); - printf(" => either change -gpgpu_shader argument in gpgpusim.config file or\n"); - printf(" modify the CUDA source to decrease the kernel block size.\n"); - abort(); - } - } - - sc->name = name; - sc->sid = sid; - - sc->RR_k = 0; - - sc->model = model; - - sc->pipeline_reg = (inst_t**) calloc(N_PIPELINE_STAGES, sizeof(inst_t*)); + m_name = name; + m_sid = shader_id; + m_tpc = tpc_id; + m_dwf_RR_k = 0; + m_pipeline_reg = (inst_t**) calloc(N_PIPELINE_STAGES, sizeof(inst_t*)); for (int j = 0; j<N_PIPELINE_STAGES; j++) { - sc->pipeline_reg[j] = (inst_t*) calloc(warp_size, sizeof(inst_t)); - for (unsigned i=0; i<warp_size; i++) { - sc->pipeline_reg[j][i] = nop_inst; - } + m_pipeline_reg[j] = (inst_t*) calloc(warp_size, sizeof(inst_t)); + for (unsigned i=0; i<warp_size; i++) + m_pipeline_reg[j][i] = inst_t(); } - if (gpgpu_pre_mem_stages) { - sc->pre_mem_pipeline = (inst_t**) calloc(gpgpu_pre_mem_stages+1, sizeof(inst_t*)); - for (unsigned j = 0; j<=gpgpu_pre_mem_stages; j++) { - sc->pre_mem_pipeline[j] = (inst_t*) calloc(pipe_simd_width, sizeof(inst_t)); - for (int i=0; i<pipe_simd_width; i++) { - sc->pre_mem_pipeline[j][i] = nop_inst; + if (m_config->gpgpu_pre_mem_stages) { + pre_mem_pipeline = (inst_t**) calloc(m_config->gpgpu_pre_mem_stages+1, sizeof(inst_t*)); + for (unsigned j = 0; j<=m_config->gpgpu_pre_mem_stages; j++) { + pre_mem_pipeline[j] = (inst_t*) calloc(warp_size, sizeof(inst_t)); + for (unsigned i=0; i<warp_size; i++) { + pre_mem_pipeline[j][i] = inst_t(); } } } - sc->n_threads = n_threads; - sc->thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), n_threads); - sc->not_completed = 0; + m_thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader); + m_not_completed = 0; - unsigned n_warp = (n_threads/warp_size) + ((n_threads%warp_size)?1:0); - sc->warp.resize(n_warp, shd_warp_t(warp_size)); - for (unsigned j = 0; j < n_warp; j++) { - sc->warp[j].wid = j; - } + m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size)); - sc->n_active_cta = 0; - for (i = 0; i<MAX_CTA_PER_SHADER; i++ ) { - sc->cta_status[i]=0; + m_n_active_cta = 0; + for (unsigned i = 0; i<MAX_CTA_PER_SHADER; i++ ) + m_cta_status[i]=0; + m_next_warp = 0; + for (unsigned i = 0; i<config->n_thread_per_shader; i++) { + m_thread[i].m_functional_model_thread_state = NULL; + m_thread[i].m_avail4fetch = false; + m_thread[i].m_waiting_at_barrier = false; + m_thread[i].m_cta_id = -1; } - //Warp variable initializations - sc->next_warp = 0; - sc->branch_priority = 0; - sc->max_branch_priority = (int*) malloc(sizeof(int)*n_threads); + #define STRSIZE 1024 + char L1D_name[STRSIZE]; + char L1T_name[STRSIZE]; + char L1C_name[STRSIZE]; + char L1I_name[STRSIZE]; - for (unsigned i = 0; i<n_threads; i++) { - sc->max_branch_priority[i] = INT_MAX; - sc->thread[i].id = i; + snprintf(L1D_name, STRSIZE, "L1D_%03d", m_sid); + m_L1D = shd_cache_create(L1D_name,m_config->gpgpu_cache_dl1_opt,1,0,m_config->gpgpu_cache_wt_through?write_through:write_back); + shd_cache_bind_logger(m_L1D, m_sid, get_shader_normal_cache_id()); - sc->thread[i].warp_priority = sc->max_branch_priority[i]; - sc->thread[i].avail4fetch = 0; - sc->thread[i].m_waiting_at_barrier = 0; + snprintf(L1T_name, STRSIZE, "L1T_%03d", m_sid); + m_L1T = shd_cache_create(L1T_name,m_config->gpgpu_cache_texl1_opt,1,0, no_writes ); + shd_cache_bind_logger(m_L1T, m_sid, get_shader_texture_cache_id()); + ptx_set_tex_cache_linesize(m_L1T->line_sz); - sc->thread[i].ptx_thd_info = NULL; - sc->thread[i].cta_id = -1; - } - - sscanf(gpgpu_cache_dl1_opt,"%d:%d:%d:%c", - &shd_n_set, &shd_linesize, &shd_n_assoc, &shd_policy); - sscanf(gpgpu_cache_texl1_opt,"%d:%d:%d:%c", - &l1tex_cache_n_set, &l1tex_cache_linesize, &l1tex_cache_n_assoc, &l1tex_cache_policy); - sscanf(gpgpu_cache_constl1_opt,"%d:%d:%d:%c", - &l1const_cache_n_set, &l1const_cache_linesize, &l1const_cache_n_assoc, &l1const_cache_policy); -#define STRSIZE 32 - char L1c_name[STRSIZE]; - char L1texc_name[STRSIZE]; - char L1constc_name[STRSIZE]; - snprintf(L1c_name, STRSIZE, "L1c_%03d", sc->sid); - sc->L1cache = shd_cache_create(L1c_name,shd_n_set,shd_n_assoc,shd_linesize,shd_policy,1,0, - gpgpu_cache_wt_through?write_through:write_back); - shd_cache_bind_logger(sc->L1cache, sc->sid, get_shader_normal_cache_id()); - snprintf(L1texc_name, STRSIZE, "L1texc_%03d", sc->sid); - sc->L1texcache = shd_cache_create(L1texc_name,l1tex_cache_n_set,l1tex_cache_n_assoc,l1tex_cache_linesize,l1tex_cache_policy,1,0, no_writes ); - shd_cache_bind_logger(sc->L1texcache, sc->sid, get_shader_texture_cache_id()); - snprintf(L1constc_name, STRSIZE, "L1constc_%03d", sc->sid); - sc->L1constcache = shd_cache_create(L1constc_name,l1const_cache_n_set,l1const_cache_n_assoc,l1const_cache_linesize,l1const_cache_policy,1,0, no_writes ); - shd_cache_bind_logger(sc->L1constcache, sc->sid, get_shader_constant_cache_id()); - //at this point, should set the parameters used by addressing schemes of all textures - ptx_set_tex_cache_linesize(l1tex_cache_linesize); - - sc->mshr_unit = new mshr_shader_unit(gpu_n_mshr_per_shader); + snprintf(L1C_name, STRSIZE, "L1C_%03d", m_sid); + m_L1C = shd_cache_create(L1C_name,m_config->gpgpu_cache_constl1_opt,1,0, no_writes ); + shd_cache_bind_logger(m_L1C, m_sid, get_shader_constant_cache_id()); - sc->fq_push = fq_push; - sc->fq_has_buffer = fq_has_buffer; - - sc->pdom_warp = (pdom_warp_ctx_t*)calloc(n_threads / warp_size, sizeof(pdom_warp_ctx_t)); - for (unsigned i = 0; i < n_threads / warp_size; ++i) { - sc->pdom_warp[i].m_stack_top = 0; - sc->pdom_warp[i].m_pc = (address_type*)calloc(warp_size * 2, sizeof(address_type)); - sc->pdom_warp[i].m_calldepth = (unsigned int*)calloc(warp_size * 2, sizeof(unsigned int)); - sc->pdom_warp[i].m_active_mask = (unsigned int*)calloc(warp_size * 2, sizeof(unsigned int)); - sc->pdom_warp[i].m_recvg_pc = (address_type*)calloc(warp_size * 2, sizeof(address_type)); - sc->pdom_warp[i].m_branch_div_cycle = (unsigned long long *)calloc(warp_size * 2, sizeof(unsigned long long )); - - memset(sc->pdom_warp[i].m_pc, -1, warp_size * 2 * sizeof(address_type)); - memset(sc->pdom_warp[i].m_calldepth, 0, warp_size * 2 * sizeof(unsigned int)); - memset(sc->pdom_warp[i].m_active_mask, 0, warp_size * 2 * sizeof(unsigned int)); - memset(sc->pdom_warp[i].m_recvg_pc, -1, warp_size * 2 * sizeof(address_type)); - } + snprintf(L1I_name, STRSIZE, "L1I_%03d", m_sid); + m_L1I = shd_cache_create(L1I_name,m_config->gpgpu_cache_il1_opt,1,0, no_writes ); + shd_cache_bind_logger(m_L1D, m_sid, get_shader_instruction_cache_id()); - sc->waiting_at_barrier = 0; + m_mshr_unit = new mshr_shader_unit(m_config); + m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader]; + for (unsigned i = 0; i < config->max_warps_per_shader; ++i) + m_pdom_warp[i] = new pdom_warp_ctx_t(i,this); + if (m_config->using_commit_queue) + m_thd_commit_queue = new fifo_pipeline<std::vector<int> >("thd_commit_queue", 0, 0,gpu_sim_cycle); + m_shader_memory_new_instruction_processed = false; - sc->last_issued_thread = sc->n_threads - 1; - - sc->using_dwf = (sc->model == DWF); - - sc->using_rrstage = (sc->model == DWF); - - sc->using_commit_queue = (sc->model == DWF - || sc->model == POST_DOMINATOR || sc->model == NO_RECONVERGE); + // Initialize scoreboard + m_scoreboard = new Scoreboard(m_sid, m_config->max_warps_per_shader); - if (sc->using_commit_queue) { - sc->thd_commit_queue = dq_create("thd_commit_queue", 0, 0, 0); + if( m_config->gpgpu_operand_collector ) { + m_operand_collector.init( m_config->gpgpu_operand_collector_num_units, + m_config->gpgpu_operand_collector_num_units_sfu, + m_config->gpgpu_num_reg_banks, this, + &m_pipeline_reg[ID_EX], + &m_pipeline_reg[OC_EX_SFU] ); } - sc->shmem_size = gpgpu_shmem_size; - sc->n_registers = gpgpu_shader_registers; - sc->n_cta = gpgpu_shader_cta; + m_memory_queue.shared.reserve(warp_size); + m_memory_queue.constant.reserve(warp_size); + m_memory_queue.texture.reserve(warp_size); + m_memory_queue.local_global.reserve(warp_size); - sc->shader_memory_new_instruction_processed = false; + // writeback + m_pl_tid = (int*) malloc(sizeof(int)*warp_size); + m_mshr_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * warp_size); + m_pl_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * warp_size); - // Initialize scoreboard - sc->scrb = new Scoreboard(sc->sid, n_warp); + // fetch + m_last_warp_fetched = 0; + m_last_warp_issued = 0; + m_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int)); + m_tmp_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int)); + m_last_warp=0; + m_last_issued_thread=0; // MIMD - if( gpgpu_operand_collector ) { - m_opndcoll_new.init( gpgpu_operand_collector_num_units, - gpgpu_operand_collector_num_units_sfu, - gpgpu_num_reg_banks, this ); + m_warp_tracker = NULL; + m_thread_pc_tracker = NULL; + if (m_config->gpgpu_no_divg_load) { + m_warp_tracker = new warp_tracker_pool(this); + m_thread_pc_tracker = new thread_pc_tracker(warp_size, config->n_thread_per_shader); } + m_fetch_tid_out = (int*) malloc(sizeof(int) * warp_size); + m_dwf_rrstage_bank_access_counter = (int*) malloc(sizeof(int) * m_config->gpgpu_dwf_rr_stage_n_reg_banks); } - -unsigned shader_reinit(shader_core_ctx_t *sc, int start_thread, int end_thread ) +void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed ) { - int i; - unsigned result=0; - - if ( gpgpu_cuda_sim ) { - unsigned cta_size = ptx_sim_cta_size(); - if ( cta_size > sc->n_threads ) { - printf("Execution error: Shader kernel CTA (block) size is too large for microarch config.\n"); - printf(" This can cause problems with applications that use __syncthreads.\n"); - printf(" CTA size (x*y*z) = %u, n_threads = %u\n", cta_size, sc->n_threads ); - printf(" => either change -gpgpu_shader argument in gpgpusim.config file or\n"); - printf(" modify the CUDA source to decrease the kernel block size.\n"); - abort(); - } + if( reset_not_completed ) + m_not_completed = 0; + m_next_warp = 0; + m_last_issued_thread=0; + for (unsigned i = start_thread; i<end_thread; i++) { + m_thread[i].n_insn = 0; + m_thread[i].m_cta_id = -1; } - - sc->next_warp = 0; - sc->branch_priority = 0; - - for (i = start_thread; i<end_thread; i++) - ptx_sim_free_sm(&sc->thread[i].ptx_thd_info); - - for (i = start_thread; i<end_thread; i++) { - sc->max_branch_priority[i] = INT_MAX; - sc->thread[i].warp_priority = sc->max_branch_priority[i]; - sc->thread[i].n_insn = 0; - sc->thread[i].cta_id = -1; + for (unsigned i = start_thread / m_config->warp_size; i < end_thread / m_config->warp_size; ++i) { + m_warp[i].reset(); + m_pdom_warp[i]->reset(); } - - for (unsigned i = start_thread / warp_size; i < end_thread / warp_size; ++i) { - sc->warp[i].reset(warp_size); - sc->pdom_warp[i].m_stack_top = 0; - memset(sc->pdom_warp[i].m_pc, -1, warp_size * 2 * sizeof(address_type)); - memset(sc->pdom_warp[i].m_calldepth, 0, warp_size * 2 * sizeof(unsigned int)); - memset(sc->pdom_warp[i].m_active_mask, 0, warp_size * 2 * sizeof(unsigned int)); - memset(sc->pdom_warp[i].m_recvg_pc, -1, warp_size * 2 * sizeof(address_type)); - memset(sc->pdom_warp[i].m_branch_div_cycle, 0, warp_size * 2 * sizeof(unsigned long long )); - } - - sc->waiting_at_barrier = 0; - sc->last_issued_thread = end_thread - 1; - - if (sc->using_commit_queue) { - if (!gpgpu_spread_blocks_across_cores) //assertion no longer holds with multiple blocks per core - assert(dq_empty(sc->thd_commit_queue)); - } - sc->pending_shmem_bkacc = 0; - sc->pending_cache_bkacc = 0; - sc->pending_cmem_acc = 0; - - //do not reset this here, shader memory may be in the middle of processing another cta's instruction. - //sc->shader_memory_new_instruction_processed = false; - - return result; } -// initialize a CTA in the shader core, currently only useful for PDOM and DWF - -void shader_init_CTA(shader_core_ctx_t *shader, int start_thread, int end_thread) +void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread ) { - int i; - int n_thread = end_thread - start_thread; - address_type start_pc = ptx_thread_get_next_pc(shader->thread[start_thread].ptx_thd_info); - if (shader->model == POST_DOMINATOR) { - int start_warp = start_thread / warp_size; - int end_warp = end_thread / warp_size + ((end_thread % warp_size)? 1 : 0); - for (i = start_warp; i < end_warp; ++i) { - shader->pdom_warp[i].m_stack_top = 0; - memset(shader->pdom_warp[i].m_pc, -1, warp_size * 2 * sizeof(address_type)); - memset(shader->pdom_warp[i].m_calldepth, 0, warp_size * 2 * sizeof(unsigned int)); - memset(shader->pdom_warp[i].m_active_mask, 0, warp_size * 2 * sizeof(unsigned int)); - memset(shader->pdom_warp[i].m_recvg_pc, -1, warp_size * 2 * sizeof(address_type)); - memset(shader->pdom_warp[i].m_branch_div_cycle, 0, warp_size * 2 * sizeof(unsigned long long )); - shader->pdom_warp[i].m_pc[0] = start_pc; - shader->pdom_warp[i].m_calldepth[0] = 1; - int t = 0; - for (t = 0; t < (int)warp_size; t++) { - if ( i * (int)warp_size + t < end_thread ) { - shader->pdom_warp[i].m_active_mask[0] |= (1 << t); + unsigned num_threads = end_thread - start_thread; + address_type start_pc = next_pc(start_thread); + if (m_config->model == POST_DOMINATOR) { + unsigned start_warp = start_thread / m_config->warp_size; + unsigned end_warp = end_thread / m_config->warp_size + ((end_thread % m_config->warp_size)? 1 : 0); + for (unsigned i = start_warp; i < end_warp; ++i) { + unsigned initial_active_mask = 0; + unsigned n_active=0; + for (unsigned t = 0; t < m_config->warp_size; t++) { + if ( i * m_config->warp_size + t < end_thread ) { + initial_active_mask |= (1 << t); + n_active++; + } } - } + m_pdom_warp[i]->launch(start_pc,initial_active_mask); + m_warp[i].init(start_pc,i,n_active); + m_not_completed += n_active; } - } else if (shader->model == DWF) { - dwf_init_CTA(shader->sid, start_thread, n_thread, start_pc); + } else if (m_config->model == DWF) { + dwf_init_CTA(m_sid, start_thread, num_threads, start_pc); + for (unsigned i = start_thread; i<end_thread; i++) + m_thread[i].m_in_scheduler = true; + } + for (unsigned tid=start_thread;tid<end_thread;tid++) { + m_thread[tid].m_avail4fetch = true; } - - for (i = start_thread; i<end_thread; i++) { - shader->thread[i].in_scheduler = 1; - } } - - - // register id for unused register slot in instruction #define DNA (0) unsigned g_next_shader_inst_uid=1; -// check to see if the fetch stage need to be stalled -int shader_fetch_stalled(shader_core_ctx_t *shader) +bool shader_core_ctx::fetch_stalled() { - int n_warp_parts = warp_size/pipe_simd_width; - - if (shader->warp_part2issue < n_warp_parts) { - return 1; - } - - for (unsigned i=0; i<warp_size; i++) { - if (shader->pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { - return 1; // stalled + for (unsigned i=0; i<m_config->warp_size; i++) { + if (m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { + return true; // stalled } } - for (int i=0; i<pipe_simd_width; i++) { - if (shader->pipeline_reg[IF_ID][i].hw_thread_id != -1 ) { - return 1; // stalled + for (unsigned i=0; i<m_config->warp_size; i++) { + if (m_pipeline_reg[IF_ID][i].hw_thread_id != -1 ) { + return true; // stalled } } - shader->warp_part2issue = 0; // reset pointer to first warp part - shader->new_warp_TS = 1; - - return 0; // not stalled + m_new_warp_TS = true; + return false; // not stalled } // initalize the pipeline stage register to nops -void shader_clear_stage_reg(shader_core_ctx_t *shader, int stage) +void shader_core_ctx::clear_stage_reg(int stage) { - for (unsigned i=0; i<warp_size; i++) { - shader->pipeline_reg[stage][i] = nop_inst; - } + clear_stage( m_pipeline_reg[stage] ); } // return the next pc of a thread -address_type shader_thread_nextpc(shader_core_ctx_t *shader, int tid) +address_type shader_core_ctx::next_pc( int tid ) const { - assert( gpgpu_cuda_sim ); - address_type pc = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info ); - return pc; + if( tid == -1 ) + return -1; + ptx_thread_info *the_thread = m_thread[tid].m_functional_model_thread_state; + if ( the_thread == NULL ) + return -1; + return the_thread->get_pc(); // PC should already be updatd to next PC at this point (was set in shader_decode() last time thread ran) } // issue thread to the warp // tid - thread id, warp_id - used by PDOM, wlane - position in warp -void shader_issue_thread(shader_core_ctx_t *shader, int tid, int wlane, unsigned active_mask ) -{ - if ( gpgpu_cuda_sim ) { - shader->pipeline_reg[TS_IF][wlane].hw_thread_id = tid; - shader->pipeline_reg[TS_IF][wlane].wlane = wlane; - shader->pipeline_reg[TS_IF][wlane].pc = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info ); - shader->pipeline_reg[TS_IF][wlane].ptx_thd_info = shader->thread[tid].ptx_thd_info; - shader->pipeline_reg[TS_IF][wlane].memreqaddr = 0; - shader->pipeline_reg[TS_IF][wlane].reg_bank_conflict_stall_checked = 0; - shader->pipeline_reg[TS_IF][wlane].reg_bank_access_pending = 0; - shader->pipeline_reg[TS_IF][wlane].uid = g_next_shader_inst_uid++; - shader->pipeline_reg[TS_IF][wlane].warp_active_mask = active_mask; - shader->pipeline_reg[TS_IF][wlane].ts_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - } - assert( shader->thread[tid].avail4fetch > 0 ); - shader->thread[tid].avail4fetch--; - assert( shader->warp[wid_from_hw_tid(tid,warp_size)].n_avail4fetch > 0 ); - shader->warp[wid_from_hw_tid(tid,warp_size)].n_avail4fetch--; -} - -void update_max_branch_priority(shader_core_ctx_t *shader, unsigned warp_hw_id, unsigned grid_num ) +void shader_core_ctx::shader_issue_thread(int tid, int wlane, unsigned active_mask ) { - int temp_max = 0; - // This means that a group of threads has completed, - // hence need to update max_priority - for (unsigned i = 0; i<warp_size; i++) { - if ( !ptx_thread_done( shader->thread[hw_tid_from_wid(warp_hw_id,warp_size,i)].ptx_thd_info ) ) { - if (shader->thread[hw_tid_from_wid(warp_hw_id,warp_size,i)].warp_priority>=temp_max) { - temp_max = shader->thread[hw_tid_from_wid(warp_hw_id,warp_size,i)].warp_priority; - } - } - } - for (unsigned i = 0; i<warp_size; i++) { - shader->max_branch_priority[hw_tid_from_wid(warp_hw_id,warp_size,i)] = temp_max; - } -} - -void shader_fetch_simd_no_reconverge(shader_core_ctx_t *shader, unsigned int shader_number, int grid_num ) -{ - int i; - int tid; - int new_tid = 0; - address_type pc = 0; - int warp_ok = 0; - int n_warp = shader->n_threads/warp_size; - int complete = 0; - - assert(gpgpu_cuda_sim); - - // First, check to see if entire program is completed, - // if it is, then break out of loop - for (unsigned i=0; i<shader->n_threads; i++) { - if (!ptx_thread_done( shader->thread[i].ptx_thd_info )) { - complete = 0; - break; - } else { - complete = 1; - } - } - if (complete) { - // printf("Shader has completed program.\n"); - return; - } - - if (shader_fetch_stalled(shader)) { - return; - } - shader_clear_stage_reg(shader, TS_IF); - - // Finds a warp where all threads in it are available for fetching - // simultaneously(all threads are not yet in pipeline, or, the ones - // that are not available, are completed already - for (i=0; i<n_warp; i++) { - int n_completed = shader->warp[shader->next_warp].n_completed; - int n_avail4fetch = shader->warp[shader->next_warp].n_avail4fetch; - if (((n_completed) == (int)warp_size) || - ((n_completed + n_avail4fetch) < (int)warp_size) ) { - //All threads in this warp have completed, hence go to next warp - //Or, some of the threads are still in pipeline - warp_ok = 0; // hey look, it's a silent register update / store instruction! (this operation is redundant) - shader->next_warp = (shader->next_warp+1)%n_warp; - } else { - int n_waiting_at_barrier = shader->warp[shader->next_warp].n_waiting_at_barrier; - if ( n_waiting_at_barrier >= (int)warp_size ) { - warp_ok = 0; // hey look, it's a silent register update / store instruction! (this operation is redundant) - continue; - } - warp_ok = 1; - break; - } - } - // None of the instructions from inside the warp can be scheduled -> should - // probably just stall, ie nops into pipeline - if (!warp_ok) { - shader_clear_stage_reg(shader, TS_IF); // NOTE: is this needed? - shader->next_warp = (shader->next_warp+1)%n_warp; // NOTE: this is not round-robin. - return; - } - - tid = warp_size*shader->next_warp; - - for (i = 0; i<(int)warp_size; i++) { - if (shader->thread[tid+i].warp_priority == shader->max_branch_priority[tid+i]) { - pc = shader_thread_nextpc(shader, tid+i); - new_tid = tid+i; - break; - } - } - //Determine which instructions inside this 'warp' will be scheduled together at this run - //If they are cannot be scheduled together then 'save' their branch priority - for (i = 0; i<(int)warp_size; i++) { - if (!ptx_thread_done( shader->thread[tid+i].ptx_thd_info )) { - address_type next_pc; - next_pc = shader_thread_nextpc(shader, tid+i); - if (next_pc != pc || - shader->thread[tid+i].warp_priority != shader->max_branch_priority[tid+i] || - shader->thread[tid+i].m_waiting_at_barrier) { - if (!ptx_thread_done( shader->thread[tid+i].ptx_thd_info )) { - if ( !shader->thread[tid + i].m_waiting_at_barrier ) { - shader->thread[tid + i].warp_priority = shader->branch_priority; - } - } - } else { - shader_issue_thread(shader, tid+i, i,(unsigned)-1); - } - } - } - shader->branch_priority++; + m_thread[tid].m_functional_model_thread_state->ptx_fetch_inst( m_pipeline_reg[TS_IF][wlane] ); + m_pipeline_reg[TS_IF][wlane].hw_thread_id = tid; + m_pipeline_reg[TS_IF][wlane].wlane = wlane; + m_pipeline_reg[TS_IF][wlane].memreqaddr = 0; + m_pipeline_reg[TS_IF][wlane].uid = g_next_shader_inst_uid++; + m_pipeline_reg[TS_IF][wlane].warp_active_mask = active_mask; + m_pipeline_reg[TS_IF][wlane].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - shader->next_warp = (shader->next_warp+1)%n_warp; + assert( m_thread[tid].m_avail4fetch ); + m_thread[tid].m_avail4fetch = false; + assert( m_warp[wid_from_hw_tid(tid,m_config->warp_size)].get_avail4fetch() > 0 ); + m_warp[wid_from_hw_tid(tid,m_config->warp_size)].dec_avail4fetch(); } -int pdom_sched_find_next_warp (shader_core_ctx_t *shader,int pdom_sched_policy, int* ready_warps - , int ready_warp_count, int* last_warp, int w_comp_c, int w_pipe_c, int w_barr_c) +int shader_core_ctx::pdom_sched_find_next_warp (int ready_warp_count) { - int n_warp = shader->n_threads/warp_size; - int i=0; - int selected_warp = ready_warps[0]; - int found =0; - - switch (pdom_sched_policy) { - case 0: - selected_warp = ready_warps[0]; //first ok warp found - found=1; - break; - case 1 ://random - selected_warp = ready_warps[rand()%ready_warp_count]; - found=1; - break; - case 8 :// execute the first available warp which is after the warp execued last time - found=0; - selected_warp = (last_warp[shader->sid] + 1 ) % n_warp; + bool found = false; + int selected_warp = m_ready_warps[0]; + switch (m_config->pdom_sched_type) { + case 0: selected_warp = m_ready_warps[0]; found=true; break; // first ok warp found + case 1: selected_warp = m_ready_warps[rand()%ready_warp_count]; found=true; break; //random + case 8: + // "loose" round robin: + // execute the next available warp which is after the warp execued last time + selected_warp = (m_last_warp + 1) % m_config->max_warps_per_shader; while (!found) { - for (i=0;i<ready_warp_count;i++) { - if (selected_warp==ready_warps[i]) { - found=1; - } + for (int i=0;i<ready_warp_count;i++) { + if (selected_warp==m_ready_warps[i]) + found=true; } - if (!found) - selected_warp = (selected_warp + 1 ) % n_warp; + if( !found ) + selected_warp = (selected_warp + 1) % m_config->max_warps_per_shader; } break; - default: - assert(0); + default: assert(0); } if (found) { - if (ready_warp_count==1) { - n_pdom_sc_single_stat++; - } else { - n_pdom_sc_orig_stat++; - } + if (ready_warp_count==1) + m_stats->n_pdom_sc_single_stat++; + else + m_stats->n_pdom_sc_orig_stat++; return selected_warp; } else { return -1; } } -void shader_fetch_simd_postdominator(shader_core_ctx_t *shader, unsigned int shader_number, int grid_num) { - int i; +void shader_core_ctx::fetch_simd_postdominator() +{ int warp_ok = 0; - int n_warp = shader->n_threads/warp_size; - int complete = 0; + bool complete = false; int tmp_warp; int warp_id; address_type check_pc = -1; - assert(gpgpu_cuda_sim); - // First, check to see if entire program is completed, // if it is, then break out of loop - for (unsigned i=0; i<shader->n_threads; i++) { - if (!ptx_thread_done( shader->thread[i].ptx_thd_info )) { - complete = 0; + for (unsigned i=0; i<m_config->n_thread_per_shader; i++) { + if (!ptx_thread_done(i)) { + complete = false; break; } else { - complete = 1; + complete = true; } } - if (complete) { + if (complete) return; - } - if (shader_fetch_stalled(shader)) { + if (fetch_stalled()) return; - } - shader_clear_stage_reg(shader, TS_IF); - - int ready_warp_count = 0; - int w_comp_c = 0 ; - int w_pipe_c = 0 ; - int w_barr_c = 0 ; - static int * ready_warps = NULL; - static int * tmp_ready_warps = NULL; - if (!ready_warps) { - ready_warps = (int*)calloc(n_warp,sizeof(int)); - } - if (!tmp_ready_warps) { - tmp_ready_warps = (int*)calloc(n_warp,sizeof(int)); - } - for (i=0; i<n_warp; i++) { - ready_warps[i]=-1; - tmp_ready_warps[i]=-1; - } + clear_stage_reg(TS_IF); - static int* last_warp; //keeps track of last warp issued per shader - if (!last_warp) { - last_warp = (int*)calloc(gpu_n_shader,sizeof(int)); + unsigned ready_warp_count = 0; + for (unsigned i=0; i<m_config->max_warps_per_shader; i++) { + m_ready_warps[i]=-1; + m_tmp_ready_warps[i]=-1; } - // Finds a warp where all threads in it are available for fetching // simultaneously(all threads are not yet in pipeline, or, the ones // that are not available, are completed already - for (i=0; i<n_warp; i++) { - int n_completed = shader->warp[shader->next_warp].n_completed; - int n_avail4fetch = shader->warp[shader->next_warp].n_avail4fetch; - - if ((n_completed) == (int)warp_size) { - //All threads in this warp have completed - w_comp_c++; - } else if ((n_completed+n_avail4fetch) < (int)warp_size) { - //some of the threads are still in pipeline - w_pipe_c++; - } else if ( shader->warp_waiting_at_barrier(shader->next_warp) ) { - w_barr_c++; - } else if ( shader_warp_scoreboard_hazard(shader, shader->next_warp) ) { - // Do nothing - warp is filtered out - //printf("SCOREBOARD COLLISION - wid=%d\n", shader->next_warp); - } else { - // A valid warp is found at this point - tmp_ready_warps[ready_warp_count] = shader->next_warp; - ready_warp_count++; + for (unsigned i=0; i<m_config->max_warps_per_shader; i++) { + if( m_warp[m_next_warp].waiting() ) { + // waiting for kernel launch, barrier, membar, atomic + } else if( (m_warp[m_next_warp].get_n_completed()+m_warp[m_next_warp].get_avail4fetch()) < m_config->warp_size) { + // waiting for instruction still in pipeline barrel processing + } else if ( !warp_scoreboard_hazard(m_next_warp) ) { + // this warp is ready and can be issued if selected + m_tmp_ready_warps[ready_warp_count] = m_next_warp; + ready_warp_count++; } - shader->next_warp = (shader->next_warp + 1) % n_warp; - } - for (i=0;i<ready_warp_count;i++) { - ready_warps[i]=tmp_ready_warps[i]; + m_next_warp = (m_next_warp + 1) % m_config->max_warps_per_shader; } - - num_warps_issuable[ready_warp_count]++; - num_warps_issuable_pershader[shader->sid]+= ready_warp_count; - + for (unsigned i=0;i<ready_warp_count;i++) + m_ready_warps[i]=m_tmp_ready_warps[i]; + m_stats->num_warps_issuable[ready_warp_count]++; + m_stats->num_warps_issuable_pershader[m_sid]+= ready_warp_count; if (ready_warp_count) { - tmp_warp = pdom_sched_find_next_warp (shader, pdom_sched_type ,ready_warps - , ready_warp_count, last_warp, w_comp_c, w_pipe_c ,w_barr_c); + tmp_warp = pdom_sched_find_next_warp (ready_warp_count); if (tmp_warp != -1) { - shader->next_warp = tmp_warp; + m_next_warp = tmp_warp; warp_ok=1; } } - static int no_warp_issued; - // None of the instructions from inside the warp can be scheduled -> should - // probably just stall, ie nops into pipeline if (!warp_ok) { - shader_clear_stage_reg(shader, TS_IF); - shader->next_warp = (shader->next_warp+1) % n_warp; - no_warp_issued = 1 ; + // None of the instructions from inside the warp can be scheduled -> should + // probably just stall, ie nops into pipeline + clear_stage_reg(TS_IF); + m_next_warp = (m_next_warp+1) % m_config->max_warps_per_shader; return; } /************************************************************/ - //at this point we have a warp to execute which is pointed to by - //shader->next_warp - - warp_id = shader->next_warp; - last_warp[shader->sid] = warp_id; - int wtid = warp_size*warp_id; + // at this point we have a warp to execute which is pointed to by next_warp - pdom_warp_ctx_t *scheduled_warp = &(shader->pdom_warp[warp_id]); + warp_id = m_next_warp; + m_last_warp = warp_id; + int wtid = m_config->warp_size*warp_id; + pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id]; // schedule threads according to active mask on the top of pdom stack - for (i = 0; i < (int)warp_size; i++) { + unsigned active_mask = scheduled_warp->get_active_mask(); + + for (unsigned i = 0; i < m_config->warp_size; i++) { unsigned int mask = (1 << i); - if ((scheduled_warp->m_active_mask[scheduled_warp->m_stack_top] & mask) == mask) { - assert (!ptx_thread_done( shader->thread[wtid+i].ptx_thd_info )); - shader_issue_thread(shader, wtid+i, i, scheduled_warp->m_active_mask[scheduled_warp->m_stack_top]); + if ((active_mask & mask) == mask) { + assert (!ptx_thread_done(wtid+i)); + shader_issue_thread(wtid+i,i,active_mask); } } - shader->next_warp = (shader->next_warp+1)%n_warp; + m_next_warp = (m_next_warp+1)%m_config->max_warps_per_shader; // check if all issued threads have the same pc - for (i = 0; i < (int) warp_size; i++) { - if ( shader->pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { + for (unsigned i = 0; i < m_config->warp_size; i++) { + if ( m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { if ( check_pc == (unsigned)-1 ) { - check_pc = shader->pipeline_reg[TS_IF][i].pc; + check_pc = m_pipeline_reg[TS_IF][i].pc; } else { - assert( check_pc == shader->pipeline_reg[TS_IF][i].pc ); + assert( check_pc == m_pipeline_reg[TS_IF][i].pc ); } } } } -bool shader_warp_scoreboard_hazard(shader_core_ctx_t *shader, int warp_id) { - static inst_t active_inst; - static op_type op = NO_OP; - static int i1, i2, i3, i4, o1, o2, o3, o4; //4 outputs needed for texture fetches in cuda-sim - static int vectorin, vectorout; - static int arch_reg[MAX_REG_OPERANDS] = { -1 }; - static int pred; - static int ar1, ar2; // address registers for memory operands +/** + * check if warp has data hazard + * + * @param warp_id + * + * @return bool : false if hazard exists + */ +bool shader_core_ctx::warp_scoreboard_hazard(int warp_id) +{ + inst_t active_inst; // Get an active thread in the warp - int wtid = warp_size*warp_id; - pdom_warp_ctx_t *scheduled_warp = &(shader->pdom_warp[warp_id]); + int wtid = m_config->warp_size*warp_id; + pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id]; thread_ctx_t *active_thread = NULL; - for (int i = 0; i < (int)warp_size; i++) { + unsigned active_mask = scheduled_warp->get_active_mask(); + for (unsigned i = 0; i < m_config->warp_size; i++) { unsigned int mask = (1 << i); - if ((scheduled_warp->m_active_mask[scheduled_warp->m_stack_top] & mask) == mask) { - active_thread = &(shader->thread[wtid+i]); + if ((active_mask & mask) == mask) { + active_thread = &(m_thread[wtid+i]); } } - if(active_thread == NULL) return false; + if(active_thread == NULL) + return false; // Decode instruction - ptx_decode_inst( active_thread->ptx_thd_info, (unsigned*)&op, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg, &pred, &ar1, &ar2); - active_inst.op = op; - active_inst.in[0] = i1; - active_inst.in[1] = i2; - active_inst.in[2] = i3; - active_inst.in[3] = i4; - active_inst.out[0] = o1; - active_inst.out[1] = o2; - active_inst.out[2] = o3; - active_inst.out[3] = o4; - active_inst.is_vectorin = vectorin; - active_inst.is_vectorout = vectorout; - active_inst.pred = pred; - active_inst.ar1 = ar1; - active_inst.ar2 = ar2; - - return shader->scrb->checkCollision(warp_id, &active_inst); + active_thread->m_functional_model_thread_state->ptx_fetch_inst( active_inst ); + return m_scoreboard->checkCollision(warp_id, &active_inst); } -void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id) { - int wtid = warp_size*warp_id; +void pdom_warp_ctx_t::pdom_update_warp_mask() +{ + int wtid = m_warp_size*m_warp_id; - pdom_warp_ctx_t *scheduled_warp = &(shader->pdom_warp[warp_id]); + pdom_warp_ctx_t *scheduled_warp = this; int stack_top = scheduled_warp->m_stack_top; @@ -1176,21 +788,21 @@ void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id) { // extract a group of threads with the same next PC among the active threads in the warp address_type tmp_next_pc = null_pc; unsigned int tmp_active_mask = 0; - void *first_active_thread=NULL; - for (int i = warp_size - 1; i >= 0; i--) { + class ptx_thread_info *first_active_thread=NULL; + for (int i = m_warp_size - 1; i >= 0; i--) { unsigned int mask = (1 << i); if ((top_active_mask & mask) == mask) { // is this thread active? - if (ptx_thread_done( shader->thread[wtid+i].ptx_thd_info )) { - top_active_mask &= ~mask; // remove completed thread from active mask - } else if (tmp_next_pc == null_pc) { - first_active_thread = shader->thread[wtid+i].ptx_thd_info; - tmp_next_pc = shader_thread_nextpc(shader, wtid+i); - tmp_active_mask |= mask; - top_active_mask &= ~mask; - } else if (tmp_next_pc == shader_thread_nextpc(shader, wtid+i)) { - tmp_active_mask |= mask; - top_active_mask &= ~mask; - } + if (m_shader->ptx_thread_done(wtid+i)) { + top_active_mask &= ~mask; // remove completed thread from active mask + } else if (tmp_next_pc == null_pc) { + first_active_thread=m_shader->get_thread_state(wtid+i); + tmp_next_pc = first_active_thread->get_pc(); + tmp_active_mask |= mask; + top_active_mask &= ~mask; + } else if (tmp_next_pc == m_shader->get_thread_state(wtid+i)->get_pc()) { + tmp_active_mask |= mask; + top_active_mask &= ~mask; + } } } @@ -1229,60 +841,102 @@ void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id) { scheduled_warp->m_stack_top = stack_top - 1; assert(scheduled_warp->m_stack_top >= 0); - assert(scheduled_warp->m_stack_top < (int)warp_size * 2); + assert(scheduled_warp->m_stack_top < m_warp_size * 2); +} + +void gpgpu_sim::get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc ) +{ + m_sc[sid]->get_pdom_stack_top_info(tid,pc,rpc); +} + +void shader_core_ctx::get_pdom_stack_top_info( unsigned tid, unsigned *pc, unsigned *rpc ) +{ + unsigned warp_id = tid/m_config->warp_size; + m_pdom_warp[warp_id]->get_pdom_stack_top_info(pc,rpc); } +void pdom_warp_ctx_t::get_pdom_stack_top_info( unsigned *pc, unsigned *rpc ) +{ + *pc = m_pc[m_stack_top]; + *rpc = m_recvg_pc[m_stack_top]; +} -void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc ) +unsigned pdom_warp_ctx_t::get_rp() const +{ + return m_recvg_pc[m_stack_top]; +} + +void pdom_warp_ctx_t::print (FILE *fout) const { - unsigned warp_id = tid/warp_size; - pdom_warp_ctx_t *warp_info = &(sc[sid]->pdom_warp[warp_id]); - unsigned idx = warp_info->m_stack_top; - *pc = warp_info->m_pc[idx]; - *rpc = warp_info->m_recvg_pc[idx]; + const pdom_warp_ctx_t *warp=this; + for ( unsigned k=0; k <= warp->m_stack_top; k++ ) { + if ( k==0 ) { + fprintf(fout, "w%02d %1u ", m_warp_id, k ); + } else { + fprintf(fout, " %1u ", k ); + } + for (unsigned m=1,j=0; j<m_warp_size; j++, m<<=1) + fprintf(fout, "%c", ((warp->m_active_mask[k] & m)?'1':'0') ); + fprintf(fout, " pc: %4u", warp->m_pc[k] ); + if ( warp->m_recvg_pc[k] == (unsigned)-1 ) { + fprintf(fout," rp: ---- cd: %2u ", warp->m_calldepth[k] ); + } else { + fprintf(fout," rp: %4u cd: %2u ", warp->m_recvg_pc[k], warp->m_calldepth[k] ); + } + if ( warp->m_branch_div_cycle[k] != 0 ) { + fprintf(fout," bd@%6u ", (unsigned) warp->m_branch_div_cycle[k] ); + } else { + fprintf(fout," " ); + } + ptx_print_insn( warp->m_pc[k], fout ); + fprintf(fout,"\n"); + } } -void shader_fetch_mimd( shader_core_ctx_t *shader, unsigned int shader_number ) + +void shader_core_ctx::new_cache_window() { - unsigned int last_issued_thread = 0; + shd_cache_new_window(m_L1D); + shd_cache_new_window(m_L1T); + shd_cache_new_window(m_L1C); +} - if (shader_fetch_stalled(shader)) { +void shader_core_ctx::fetch_mimd() +{ + if (fetch_stalled()) return; - } - shader_clear_stage_reg(shader, TS_IF); + clear_stage_reg(TS_IF); - // some form of barrel processing: - // - checking availability from the thread after the last issued thread - for (int i=0, j=0;i<(int)shader->n_threads && j< (int) warp_size;i++) { - int thd_id = (i + shader->last_issued_thread + 1) % shader->n_threads; - if (shader->thread[thd_id].avail4fetch && !shader->thread[thd_id].m_waiting_at_barrier ) { - shader_issue_thread(shader, thd_id, j,(unsigned)-1); - last_issued_thread = thd_id; + for (unsigned i=0, j=0;i<m_config->n_thread_per_shader && j< m_config->warp_size;i++) { + int thd_id = (i + m_last_issued_thread + 1) % m_config->n_thread_per_shader; + if (m_thread[thd_id].m_avail4fetch && !m_thread[thd_id].m_waiting_at_barrier ) { + shader_issue_thread(thd_id, j,(unsigned)-1); + m_last_issued_thread = thd_id; j++; } } - shader->last_issued_thread = last_issued_thread; } // seperate the incoming warp into multiple warps with seperate pcs -int split_warp_by_pc(int *tid_in, shader_core_ctx_t *shader, int **tid_split, address_type *pc) { +int shader_core_ctx::split_warp_by_pc(int *tid_in, int **tid_split, address_type *pc) +{ unsigned n_pc = 0; static int *pc_cnt = NULL; // count the number of threads with the same pc assert(tid_in); assert(tid_split); assert(pc); - memset(pc,0,sizeof(address_type)*warp_size); + memset(pc,0,sizeof(address_type)*m_config->warp_size); - if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*warp_size); - memset(pc_cnt,0,sizeof(int)*warp_size); + if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size); + memset(pc_cnt,0,sizeof(int)*m_config->warp_size); // go through each thread in the given warp - for (unsigned i=0; i< warp_size; i++) { + for (unsigned i=0; i< m_config->warp_size; i++) { if (tid_in[i] < 0) continue; int matched = 0; address_type thd_pc; - thd_pc = shader_thread_nextpc(shader, tid_in[i]); + thd_pc = next_pc(tid_in[i]); // check to see if the pc has occured before for (unsigned j=0; j<n_pc; j++) { @@ -1295,7 +949,7 @@ int split_warp_by_pc(int *tid_in, shader_core_ctx_t *shader, int **tid_split, ad } // if not, put the tid in a seperate warp if (!matched) { - assert(n_pc < warp_size); + assert(n_pc < m_config->warp_size); tid_split[n_pc][0] = tid_in[i]; pc[n_pc] = thd_pc; pc_cnt[n_pc] = 1; @@ -1306,12 +960,12 @@ int split_warp_by_pc(int *tid_in, shader_core_ctx_t *shader, int **tid_split, ad } // see if this warp just executed the barrier instruction -int warp_reached_barrier(int *tid_in, shader_core_ctx_t *shader) +int shader_core_ctx::warp_reached_barrier(int *tid_in) { int reached_barrier = 0; - for (unsigned i=0; i<warp_size; i++) { + for (unsigned i=0; i<m_config->warp_size; i++) { if (tid_in[i] < 0) continue; - if (shader->thread[tid_in[i]].m_reached_barrier) { + if (m_thread[tid_in[i]].m_reached_barrier) { reached_barrier = 1; break; } @@ -1320,26 +974,27 @@ int warp_reached_barrier(int *tid_in, shader_core_ctx_t *shader) } // seperate the incoming warp into multiple warps with seperate pcs and cta -int split_warp_by_cta(int *tid_in, shader_core_ctx_t *shader, int **tid_split, address_type *pc, int *cta) { +int shader_core_ctx::split_warp_by_cta(int *tid_in, int **tid_split, address_type *pc, int *cta) +{ unsigned n_pc = 0; static int *pc_cnt = NULL; // count the number of threads with the same pc assert(tid_in); assert(tid_split); assert(pc); - memset(pc,0,sizeof(address_type)*warp_size); + memset(pc,0,sizeof(address_type)*m_config->warp_size); - if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*warp_size); - memset(pc_cnt,0,sizeof(int)*warp_size); + if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size); + memset(pc_cnt,0,sizeof(int)*m_config->warp_size); // go through each thread in the given warp - for (unsigned i=0; i<warp_size; i++) { + for (unsigned i=0; i<m_config->warp_size; i++) { if (tid_in[i] < 0) continue; int matched = 0; address_type thd_pc; - thd_pc = shader_thread_nextpc(shader, tid_in[i]); + thd_pc = next_pc(tid_in[i]); - int thd_cta = ptx_thread_get_cta_uid( shader->thread[tid_in[i]].ptx_thd_info ); + int thd_cta = ptx_thread_get_cta_uid( m_thread[tid_in[i]].m_functional_model_thread_state ); // check to see if the pc has occured before for (unsigned j=0; j<n_pc; j++) { @@ -1352,7 +1007,7 @@ int split_warp_by_cta(int *tid_in, shader_core_ctx_t *shader, int **tid_split, a } // if not, put the tid in a seperate warp if (!matched) { - assert(n_pc < warp_size); + assert(n_pc < m_config->warp_size); tid_split[n_pc][0] = tid_in[i]; pc[n_pc] = thd_pc; cta[n_pc] = thd_cta; @@ -1363,638 +1018,508 @@ int split_warp_by_cta(int *tid_in, shader_core_ctx_t *shader, int **tid_split, a return n_pc; } -void shader_fetch_simd_dwf( shader_core_ctx_t *shader, unsigned int shader_number ) { - +void shader_core_ctx::fetch_simd_dwf() +{ static int *tid_in = NULL; static int *tid_out = NULL; if (!tid_in) { - tid_in = (int*) malloc(sizeof(int)*warp_size); - memset(tid_in, -1, sizeof(int)*warp_size); + tid_in = (int*) malloc(sizeof(int)*m_config->warp_size); + memset(tid_in, -1, sizeof(int)*m_config->warp_size); } if (!tid_out) { - tid_out = (int*) malloc(sizeof(int)*warp_size); - memset(tid_out, -1, sizeof(int)*warp_size); + tid_out = (int*) malloc(sizeof(int)*m_config->warp_size); + memset(tid_out, -1, sizeof(int)*m_config->warp_size); } static int **tid_split = NULL; if (!tid_split) { - tid_split = (int**)malloc(sizeof(int*)*warp_size); - tid_split[0] = (int*)malloc(sizeof(int)*warp_size*warp_size); - for (unsigned i=1; i<warp_size; i++) { - tid_split[i] = tid_split[0] + warp_size * i; + tid_split = (int**)malloc(sizeof(int*)*m_config->warp_size); + tid_split[0] = (int*)malloc(sizeof(int)*m_config->warp_size*m_config->warp_size); + for (unsigned i=1; i<m_config->warp_size; i++) { + tid_split[i] = tid_split[0] + m_config->warp_size * i; } } static address_type *thd_pc = NULL; - if (!thd_pc) thd_pc = (address_type*)malloc(sizeof(address_type)*warp_size); + if (!thd_pc) thd_pc = (address_type*)malloc(sizeof(address_type)*m_config->warp_size); static int *thd_cta = NULL; - if (!thd_cta) thd_cta = (int*)malloc(sizeof(int)*warp_size); + if (!thd_cta) thd_cta = (int*)malloc(sizeof(int)*m_config->warp_size); int warpupdate_bw = 1; - while (!dq_empty(shader->thd_commit_queue) && warpupdate_bw > 0) { + while (!m_thd_commit_queue->empty() && warpupdate_bw > 0) { // grab a committed warp, split it into multiple BRUs (tid_split) by PC - int *tid_commit = (int*)dq_pop(shader->thd_commit_queue); - memset(tid_split[0], -1, sizeof(int)*warp_size*warp_size); - memset(thd_pc, 0, sizeof(address_type)*warp_size); - memset(thd_cta, -1, sizeof(int)*warp_size); + std::vector<int> *tid_commit = m_thd_commit_queue->pop(gpu_sim_cycle); + memset(tid_split[0], -1, sizeof(int)*m_config->warp_size*m_config->warp_size); + memset(thd_pc, 0, sizeof(address_type)*m_config->warp_size); + memset(thd_cta, -1, sizeof(int)*m_config->warp_size); - int reached_barrier = warp_reached_barrier(tid_commit, shader); + int reached_barrier = warp_reached_barrier(tid_commit->data()); unsigned n_warp_update; if (reached_barrier) { - n_warp_update = split_warp_by_cta(tid_commit, shader, tid_split, thd_pc, thd_cta); + n_warp_update = split_warp_by_cta(tid_commit->data(), tid_split, thd_pc, thd_cta); } else { - n_warp_update = split_warp_by_pc(tid_commit, shader, tid_split, thd_pc); + n_warp_update = split_warp_by_pc(tid_commit->data(), tid_split, thd_pc); } - if (n_warp_update > 2) gpgpu_commit_pc_beyond_two++; + if (n_warp_update > 2) m_stats->gpgpu_commit_pc_beyond_two++; warpupdate_bw -= n_warp_update; // put the splitted warp updates into the DWF scheduler for (unsigned i=0;i<n_warp_update;i++) { - for (unsigned j=0;j<warp_size;j++) { + for (unsigned j=0;j<m_config->warp_size;j++) { if (tid_split[i][j] < 0) continue; - assert(shader->thread[tid_split[i][j]].avail4fetch); - assert(!shader->thread[tid_split[i][j]].in_scheduler); - shader->thread[tid_split[i][j]].in_scheduler = 1; + assert(m_thread[tid_split[i][j]].m_avail4fetch); + assert(!m_thread[tid_split[i][j]].m_in_scheduler); + m_thread[tid_split[i][j]].m_in_scheduler = true; } - dwf_clear_accessed(shader->sid); + dwf_clear_accessed(m_sid); if (reached_barrier) { - dwf_update_warp_at_barrier(shader->sid, tid_split[i], thd_pc[i], thd_cta[i]); + dwf_update_warp_at_barrier(m_sid, tid_split[i], thd_pc[i], thd_cta[i]); } else { - dwf_update_warp(shader->sid, tid_split[i], thd_pc[i]); + dwf_update_warp(m_sid, tid_split[i], thd_pc[i]); } } - free_commit_warp(tid_commit); + delete tid_commit; } // Track the #PC right after the warps are input to the scheduler - dwf_update_statistics(shader->sid); - dwf_clear_policy_access(shader->sid); + dwf_update_statistics(m_sid); + dwf_clear_policy_access(m_sid); - if (shader_fetch_stalled(shader)) { + if (fetch_stalled()) { return; } - shader_clear_stage_reg(shader, TS_IF); + clear_stage_reg(TS_IF); address_type scheduled_pc; - dwf_issue_warp(shader->sid, tid_out, &scheduled_pc); + dwf_issue_warp(m_sid, tid_out, &scheduled_pc); - for (unsigned i=0; i<warp_size; i++) { + for (unsigned i=0; i<m_config->warp_size; i++) { int issue_tid = tid_out[i]; if (issue_tid >= 0) { - shader_issue_thread(shader, issue_tid, i, (unsigned)-1); - shader->thread[issue_tid].in_scheduler = 0; - shader->thread[issue_tid].m_reached_barrier = 0; - shader->last_issued_thread = issue_tid; - assert(shader->pipeline_reg[TS_IF][i].pc == scheduled_pc); + shader_issue_thread(issue_tid, i, (unsigned)-1); + m_thread[issue_tid].m_in_scheduler = false; + m_thread[issue_tid].m_reached_barrier = false; + assert(m_pipeline_reg[TS_IF][i].pc == scheduled_pc); } } } -void print_shader_cycle_distro( FILE *fout ) +void gpgpu_sim::print_shader_cycle_distro( FILE *fout ) const { fprintf(fout, "Warp Occupancy Distribution:\n"); - fprintf(fout, "Stall:%d\t", shader_cycle_distro[0]); - fprintf(fout, "W0_Idle:%d\t", shader_cycle_distro[1]); - fprintf(fout, "W0_Mem:%d", shader_cycle_distro[2]); - for (unsigned i = 3; i < warp_size + 3; i++) { - fprintf(fout, "\tW%d:%d", i-2, shader_cycle_distro[i]); + fprintf(fout, "Stall:%d\t", m_shader_stats->shader_cycle_distro[0]); + fprintf(fout, "W0_Idle:%d\t", m_shader_stats->shader_cycle_distro[1]); + fprintf(fout, "W0_Mem:%d", m_shader_stats->shader_cycle_distro[2]); + for (unsigned i = 3; i < m_shader_config->warp_size + 3; i++) { + fprintf(fout, "\tW%d:%d", i-2, m_shader_stats->shader_cycle_distro[i]); } fprintf(fout, "\n"); } -void inflight_memory_insn_add( shader_core_ctx_t *shader, inst_t *mem_insn) + +#define PROGRAM_MEM_START 0xF0000000 /* should be distinct from other memory spaces... + check ptx_ir.h to verify this does not overlap + other memory spaces */ +void shader_core_ctx::fetch_new() { - if (enable_ptx_file_line_stats) { - ptx_file_line_stats_add_inflight_memory_insn(shader->sid, mem_insn->pc); - } + if( m_inst_fetch_buffer.m_valid ) { + // decode 1 or 2 instructions and place them into ibuffer + address_type pc = m_inst_fetch_buffer.m_pc; + const inst_t* pI1 = ptx_fetch_inst(pc); + assert(pI1); + m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(0,pI1); + m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline(); + const inst_t* pI2 = ptx_fetch_inst(pc+pI1->isize); + if( pI2 ) { + m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(1,pI2); + m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline(); + } + m_inst_fetch_buffer.m_valid = false; + } + + if( !m_inst_fetch_buffer.m_valid ) { + // find an active warp with space in instruction buffer that is not already waiting on a cache miss + // and get next 1-2 instructions from i-cache... + for( unsigned i=0; i < m_config->max_warps_per_shader; i++ ) { + unsigned warp_id = (m_last_warp_fetched+1+i) % m_config->max_warps_per_shader; + if( m_warp[warp_id].done() && !m_scoreboard->pendingWrites(warp_id) && !m_warp[warp_id].done_exit() + && m_warp[warp_id].stores_done() && !m_warp[warp_id].inst_in_pipeline() ) { + bool did_exit=false; + for( unsigned t=0; t<m_config->warp_size;t++) { + unsigned tid=warp_id*m_config->warp_size+t; + if( m_thread[tid].m_functional_model_thread_state ) { + register_cta_thread_exit(tid); + m_not_completed -= 1; + m_thread[tid].m_functional_model_thread_state=NULL; + did_exit=true; + } + } + if( did_exit ) + m_warp[warp_id].set_done_exit(); + } + if( !m_warp[warp_id].done() && !m_warp[warp_id].imiss_pending() && m_warp[warp_id].ibuffer_empty() ) { + address_type pc = m_warp[warp_id].get_pc(); + address_type ppc = pc + PROGRAM_MEM_START; + address_type wb=0; + unsigned nbytes=16; + unsigned offset_in_block = pc & (m_L1I->line_sz-1); + if( (offset_in_block+nbytes) > m_L1I->line_sz ) + nbytes = (m_L1I->line_sz-offset_in_block); + enum cache_request_status status = shd_cache_access_new( m_L1I, (unsigned long long)pc, nbytes, 0, gpu_sim_cycle, &wb ); + if( status != HIT ) { + unsigned req_size = READ_PACKET_SIZE; + if( m_gpu->fq_has_buffer(ppc, req_size, false, m_sid) ) { + m_last_warp_fetched=warp_id; + mshr_entry *mshr = new mshr_entry(); + mshr->init(ppc,false,instruction_space,warp_id); + fq_push( pc, req_size, false, + NO_PARTIAL_WRITE, + warp_id, + mshr, 0, + INST_ACC_R, pc ); + m_warp[warp_id].set_imiss_pending(mshr); + m_warp[warp_id].set_last_fetch(gpu_sim_cycle); + } + } else { + m_last_warp_fetched=warp_id; + m_inst_fetch_buffer = ifetch_buffer_t(pc,nbytes,warp_id); + m_warp[warp_id].set_last_fetch(gpu_sim_cycle); + } + break; + } + } + } } -void inflight_memory_insn_sub( shader_core_ctx_t *shader, inst_t *mem_insn) +int is_load ( const inst_t &inst ) { - if (enable_ptx_file_line_stats) { - ptx_file_line_stats_sub_inflight_memory_insn(shader->sid, mem_insn->pc); - } + return (inst.op == LOAD_OP || inst.memory_op == memory_load); } -void report_exposed_memory_latency( shader_core_ctx_t *shader ) +int is_store ( const inst_t &inst ) { - if (enable_ptx_file_line_stats) { - ptx_file_line_stats_commit_exposed_latency(shader->sid, 1); - } + return (inst.op == STORE_OP || inst.memory_op == memory_store); } -static int gpgpu_warp_occ_detailed = 0; -static int **warp_occ_detailed = NULL; - -void check_stage_pcs( shader_core_ctx_t *shader, unsigned stage ); -void check_pm_stage_pcs( shader_core_ctx_t *shader, unsigned stage ); +int is_const ( memory_space_t space ) +{ + return((space.get_type() == const_space) || (space == param_space_kernel)); +} -void shader_fetch( shader_core_ctx_t *shader, unsigned int shader_number, int grid_num ) +int is_local ( memory_space_t space ) { - assert(shader->model < NUM_SIMD_MODEL); - int n_warp_parts = warp_size/pipe_simd_width; + return (space == local_space) || (space == param_space_local); +} - // check if decode stage is stalled - int decode_stalled = 0; - for (int i = 0; i < pipe_simd_width; i++) { - if (shader->pipeline_reg[IF_ID][i].hw_thread_id != -1 ) - decode_stalled = 1; - } - if (shader->gpu_cycle % n_warp_parts == 0) { +void shader_core_ctx::ptx_exec_inst( inst_t &inst ) +{ + m_thread[inst.hw_thread_id].m_functional_model_thread_state->ptx_exec_inst(inst); + if( inst.callback.function != NULL ) + m_warp[inst.hw_thread_id/m_config->warp_size].inc_n_atomic(); + if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst))) + inst.memreqaddr = translate_local_memaddr(inst.memreqaddr, inst.hw_thread_id, m_gpu->num_shader()); +} - switch (shader->model) { - case NO_RECONVERGE: - shader_fetch_simd_no_reconverge(shader, shader_number, grid_num ); - break; - case POST_DOMINATOR: - shader_fetch_simd_postdominator(shader, shader_number, grid_num); - break; - case MIMD: - shader_fetch_mimd(shader, shader_number); - break; - case DWF: - shader_fetch_simd_dwf(shader, shader_number); - break; - default: - fprintf(stderr, "Unknown scheduler: %d\n", shader->model); - assert(0); - break; - } +void shader_core_ctx::issue_warp( const inst_t *pI, unsigned active_mask, inst_t *&warp, unsigned warp_id ) +{ + m_warp[warp_id].ibuffer_free(); + assert(pI->valid()); + unsigned cta_id = (unsigned)-1; + for ( unsigned t=0; t < m_config->warp_size; t++ ) { + unsigned tid=m_config->warp_size*warp_id+t; + warp[t] = *pI; + warp[t].warp_active_mask = active_mask; + if( active_mask & (1<<t) ) { + cta_id = m_thread[tid].m_cta_id; + warp[t].hw_thread_id = tid; + warp[t].wlane = t; + warp[t].uid = g_next_shader_inst_uid++; + warp[t].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; + ptx_exec_inst( warp[t] ); + if ( ptx_thread_done(tid) ) { + m_warp[warp_id].inc_n_completed(); + m_warp[warp_id].ibuffer_flush(); + } + } + } + assert( cta_id != (unsigned)-1 ); + if( pI->op == BARRIER_OP ) + set_at_barrier(cta_id,warp_id); + else if( pI->op == MEMORY_BARRIER_OP ) + set_at_memory_barrier(warp_id); + m_pdom_warp[warp_id]->pdom_update_warp_mask(); + m_scoreboard->reserveRegisters(warp_id, pI); + m_warp[warp_id].set_next_pc(pI->pc + pI->isize); - static int *tid_out = NULL; - if (!tid_out) { - tid_out = (int*) malloc(sizeof(int) * warp_size); - } - memset(tid_out, -1, sizeof(int)*warp_size); + ///// + memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size); + int n_thd_in_warp = 0; + for (unsigned i=0; i<m_config->warp_size; i++) { + m_fetch_tid_out[i] = warp[i].hw_thread_id; + if (m_fetch_tid_out[i] >= 0) + n_thd_in_warp += 1; + } - if (!shader_cycle_distro) { - shader_cycle_distro = (unsigned int*) calloc(warp_size + 3, sizeof(unsigned int)); - } + m_new_warp_TS = false; - if (gpgpu_no_divg_load && shader->new_warp_TS && !decode_stalled) { - int n_thd_in_warp = 0; - address_type pc_out = 0xDEADBEEF; - for (unsigned i=0; i<warp_size; i++) { - tid_out[i] = shader->pipeline_reg[TS_IF][i].hw_thread_id; - if (tid_out[i] >= 0) { - n_thd_in_warp += 1; - pc_out = shader->pipeline_reg[TS_IF][i].pc; + // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp + assert( n_thd_in_warp > 0 ); + m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pI->pc, n_thd_in_warp,m_config->warp_size); +} + +void shader_core_ctx::decode_new() +{ + for ( unsigned i=0; i < m_config->max_warps_per_shader; i++ ) { + unsigned warp_id = (m_last_warp_issued+1+i) % m_config->max_warps_per_shader; + unsigned checked=0; + unsigned issued=0; + while( !m_warp[warp_id].waiting() && !m_warp[warp_id].ibuffer_empty() && (checked < 2) && (issued < 2) ) { + unsigned active_mask = m_pdom_warp[warp_id]->get_active_mask(); + const inst_t *pI = m_warp[warp_id].ibuffer_next(); + unsigned pc,rpc; + m_pdom_warp[warp_id]->get_pdom_stack_top_info(&pc,&rpc); + if( pI ) { + if( pc != pI->pc ) { + // control hazard + m_warp[warp_id].set_next_pc(pc); + m_warp[warp_id].ibuffer_flush(); + } else if ( !m_scoreboard->checkCollision(warp_id, pI) ) { + assert( m_warp[warp_id].inst_in_pipeline() ); + if ( (pI->op != SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC]) ) { + issue_warp(pI, active_mask, m_pipeline_reg[ID_OC], warp_id); + issued++; + } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC_SFU]) ) { + issue_warp(pI, active_mask, m_pipeline_reg[ID_OC_SFU], warp_id); + issued++; + } + } } - } + m_warp[warp_id].ibuffer_step(); + checked++; + } + if ( issued ) { + m_last_warp_issued=warp_id; + break; + } + } +} + +void shader_core_ctx::fetch() +{ + // check if decode stage is stalled + bool decode_stalled = !pipeline_regster_empty( m_pipeline_reg[IF_ID] ); - //wpt_register_warp(tid_out, shader); - get_warp_tracker_pool().wpt_register_warp(tid_out, shader, pc_out); + // find a ready warp and put it in the TS_IF pipeline register + switch (m_config->model) { + case POST_DOMINATOR: fetch_simd_postdominator(); break; + case DWF: fetch_simd_dwf(); break; + case MIMD: fetch_mimd(); break; + default: fprintf(stderr, "Unknown scheduler: %d\n", m_config->model); assert(0); break; + } - if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) { - track_thread_pc( shader->sid, tid_out, pc_out ); - } - if (gpgpu_cflog_interval != 0) { - insn_warp_occ_log( shader->sid, pc_out, n_thd_in_warp); - shader_warp_occ_log( shader->sid, n_thd_in_warp); - } - if ( gpgpu_warpdistro_shader < 0 || shader->sid == gpgpu_warpdistro_shader ) { - shader_cycle_distro[n_thd_in_warp + 2] += 1; - if (n_thd_in_warp == 0) { - if (shader->pending_mem_access == 0) shader_cycle_distro[1]++; - } - } - shader->new_warp_TS = 0; + memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size); - if (enable_ptx_file_line_stats && n_thd_in_warp > 0) { - //ptx_file_line_stats_add_warp_issued(pc_out); - //ptx_file_line_stats_add_warp_occ_total(pc_out, n_thd_in_warp); + if (m_config->gpgpu_no_divg_load && m_new_warp_TS && !decode_stalled) { + + // count number of active threads in this warp, determine PC value + // record active threads in tid_out + int n_thd_in_warp = 0; + address_type pc_out = 0xDEADBEEF; + for (unsigned i=0; i<m_config->warp_size; i++) { + m_fetch_tid_out[i] = m_pipeline_reg[TS_IF][i].hw_thread_id; + if (m_fetch_tid_out[i] >= 0) { + n_thd_in_warp += 1; + pc_out = m_pipeline_reg[TS_IF][i].pc; } + } - if ( gpgpu_warp_occ_detailed && - n_thd_in_warp && (shader->model == POST_DOMINATOR) ) { - int n_warp = gpu_n_thread_per_shader / warp_size; - if (!warp_occ_detailed) { - warp_occ_detailed = (int**) malloc(sizeof(int*) * gpu_n_shader * n_warp); - warp_occ_detailed[0] = (int*) calloc(sizeof(int), gpu_n_shader * n_warp * warp_size); - for (unsigned i = 0; i < n_warp * gpu_n_shader; i++) { - warp_occ_detailed[i] = warp_occ_detailed[0] + i * warp_size; - } - } + m_new_warp_TS = false; - int wid = -1; - for (unsigned i=0; i<warp_size; i++) { - if (tid_out[i] >= 0) wid = tid_out[i] / warp_size; - } - assert(wid != -1); - warp_occ_detailed[shader->sid * n_warp + wid][n_thd_in_warp - 1] += 1; + // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp + if( n_thd_in_warp > 0 ) + m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pc_out, n_thd_in_warp,m_config->warp_size); - if (shader->sid == 0 && wid == 16 && 0) { - printf("wtrace[%08x] ", pc_out); - for (unsigned i=0; i<warp_size; i++) { - printf("%03d ", tid_out[i]); - } - printf("\n"); - } - } - } else { - if ( gpgpu_warpdistro_shader < 0 || shader->sid == gpgpu_warpdistro_shader ) { - shader_cycle_distro[0] += 1; - } + // some statistics collection + if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) + m_thread_pc_tracker->set_threads_pc( m_fetch_tid_out, pc_out ); + if (gpgpu_cflog_interval != 0) { + insn_warp_occ_log( m_sid, pc_out, n_thd_in_warp); + shader_warp_occ_log( m_sid, n_thd_in_warp); + } + if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) { + m_stats->shader_cycle_distro[n_thd_in_warp + 2] += 1; + if (n_thd_in_warp == 0) + if (m_pending_mem_access == 0) + m_stats->shader_cycle_distro[1]++; + } + } else { + if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) { + m_stats->shader_cycle_distro[0] += 1; } + } - if (!decode_stalled) { - for (unsigned i = 0; i < warp_size; i++) { - int tid_tsif = shader->pipeline_reg[TS_IF][i].hw_thread_id; - address_type pc_out = shader->pipeline_reg[TS_IF][i].pc; - cflog_update_thread_pc(shader->sid, tid_tsif, pc_out); - } + if (!decode_stalled) { + for (unsigned i = 0; i < m_config->warp_size; i++) { + int tid_tsif = m_pipeline_reg[TS_IF][i].hw_thread_id; + address_type pc_out = m_pipeline_reg[TS_IF][i].pc; + cflog_update_thread_pc(m_sid, tid_tsif, pc_out); } + } - if (enable_ptx_file_line_stats && !decode_stalled) { - int TS_stage_empty = 1; - for (unsigned i = 0; i < warp_size; i++) { - if (shader->pipeline_reg[TS_IF][i].hw_thread_id >= 0) { - TS_stage_empty = 0; - break; - } - } - if (TS_stage_empty) { - report_exposed_memory_latency(shader); + if (enable_ptx_file_line_stats && !decode_stalled) { + int TS_stage_empty = 1; + for (unsigned i = 0; i < m_config->warp_size; i++) { + if (m_pipeline_reg[TS_IF][i].hw_thread_id >= 0) { + TS_stage_empty = 0; + break; } } + if (TS_stage_empty) { + if (enable_ptx_file_line_stats) + ptx_file_line_stats_commit_exposed_latency(m_sid, 1); + } } // if not, send the warp part to decode stage - if (!decode_stalled && shader->warp_part2issue < n_warp_parts) { - check_stage_pcs(shader,TS_IF); - for (int i = 0; i < pipe_simd_width; i++) { - int wlane_idx = shader->warp_part2issue * pipe_simd_width + i; - shader->pipeline_reg[IF_ID][i] = shader->pipeline_reg[TS_IF][wlane_idx]; - shader->pipeline_reg[IF_ID][i].if_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - shader->pipeline_reg[TS_IF][wlane_idx] = nop_inst; - } - shader->warp_part2issue += 1; + if (!decode_stalled) { + check_stage_pcs(TS_IF); + inst_t *fvi = first_valid_thread(m_pipeline_reg[TS_IF]); + if( fvi ) + m_warp[fvi->hw_thread_id/m_config->warp_size].set_last_fetch(gpu_sim_cycle); + move_warp(m_pipeline_reg[IF_ID],m_pipeline_reg[TS_IF]); } } -inline int is_load ( op_type op ) { - return op == LOAD_OP; -} - -inline int is_store ( op_type op ) { - return op == STORE_OP; -} - -inline int is_tex ( memory_space_t space ) { - return((space) == tex_space); -} - -inline int is_const ( memory_space_t space ) { - return((space.get_type() == const_space) || (space == param_space_kernel)); -} - -inline int is_local ( memory_space_t space ) { - return (space == local_space) || (space == param_space_local); -} - -inline int is_param ( memory_space_t space ) { - return (space == param_space_kernel); -} - -inline int is_shared ( memory_space_t space ) { - return((space) == shared_space); -} - -inline int shmem_bank ( address_type addr ) { - return((int)(addr/((address_type)WORD_SIZE)) % gpgpu_n_shmem_bank); -} - -inline int cache_bank ( address_type addr, shader_core_ctx_t *shader ) { - return(int)( addr >> (address_type)shader->L1cache->line_sz_log2 ) & ( gpgpu_n_cache_bank - 1 ); -} - -inline address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes) +address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes) { return (addr >> segment_size_lg2bytes); } - -inline address_type translate_local_memaddr(address_type localaddr, shader_core_ctx_t *shader, int tid) +address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader ) { // During functional execution, each thread sees its own memory space for local memory, but these // need to be mapped to a shared address space for timing simulation. We do that mapping here. - localaddr -= 0x100; localaddr /=4; - if (gpgpu_local_mem_map) { + if (m_config->gpgpu_local_mem_map) { // Dnew = D*nTpC*nCpS*nS + nTpC*C + T%nTpC // C = S + nS*(T/nTpC) // D = data index; T = thread; C = CTA; S = shader core; p = per // keep threads in a warp contiguous // then distribute across memory space by CTAs from successive shader cores first, // then by successive CTA in same shader core - localaddr *= gpu_padded_cta_size * gpu_max_cta_per_shader * gpu_n_shader; - localaddr += gpu_padded_cta_size * (shader->sid + gpu_n_shader * (tid / gpu_padded_cta_size)); - localaddr += tid % gpu_padded_cta_size; + localaddr *= m_config->gpu_padded_cta_size * m_config->gpu_max_cta_per_shader * num_shader; + localaddr += m_config->gpu_padded_cta_size * (m_sid + num_shader * (tid / m_config->gpu_padded_cta_size)); + localaddr += tid % m_config->gpu_padded_cta_size; } else { // legacy mapping that maps the same address in the local memory space of all threads // to a single contiguous address region - localaddr *= gpu_n_shader * gpu_n_thread_per_shader; - localaddr += (gpu_n_thread_per_shader*shader->sid) + tid; + localaddr *= num_shader * m_config->n_thread_per_shader; + localaddr += (m_config->n_thread_per_shader *m_sid) + tid; } localaddr *= 4; - localaddr += 0x100; return localaddr; } ///////////////////////////////////////////////////////////////////////////////////////// -// Register Bank Conflict Structures - -bool gpgpu_reg_bank_conflict_model; - -#define MAX_REG_BANKS 32 -unsigned int gpgpu_num_reg_banks; // this needs to be less than MAX_REG_BANKS -bool gpgpu_reg_bank_use_warp_id; - -#define MAX_BANK_CONFLICT 8 /* tex can have four source and four destination regs */ - -class reg_bank_access { -public: - reg_bank_access():tot(0),rd(0),wr(0){ - for (unsigned i = 0; i < 4; i++) rd_regs[i] = -1; - } - unsigned tot; - unsigned rd; - unsigned wr; - int rd_regs[4]; -}; - -int register_bank(int regnum, int tid) -{ - int bank = regnum; - if (gpgpu_reg_bank_use_warp_id) - bank += tid >> 5/*log2(warp_size)*/; - return bank % gpgpu_num_reg_banks; -} - -reg_bank_access g_reg_bank_access[MAX_REG_BANKS]; - -// just to use as "shorthand" for clearing accesses each cycle -static const struct reg_bank_access empty_reg_bank_access; - -unsigned int gpu_reg_bank_conflict_stalls = 0; -void shader_opnd_collect_read(shader_core_ctx_t* shader) +void shader_core_ctx::decode() { - const int prevstage = ID_OC; - shader->m_opndcoll_new.step(shader->pipeline_reg[prevstage]); -} - -void shader_opnd_collect_write(shader_core_ctx_t* shader) -{ - shader->m_opndcoll_new.writeback(shader->pipeline_reg[WB_RT]); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void shader_decode( shader_core_ctx_t *shader, - unsigned int shader_number, - unsigned int grid_num ) { - - address_type addr; - dram_callback_t callback; op_type op = NO_OP; - int tid; - int i1, i2, i3, i4, o1, o2, o3, o4; //4 outputs needed for texture fetches in cuda-sim - int i; - int touched_priority=0; - int warp_tid=0; - unsigned data_size; - memory_space_t space; - unsigned cycles; - int vectorin, vectorout; - int arch_reg[MAX_REG_OPERANDS] = { -1 }; - int pred; - int ar1, ar2; // address registers for memory operands + unsigned warp_id = -1; + unsigned cta_id = -1; + address_type regs_regs_PC = 0xDEADBEEF; address_type warp_current_pc = 0x600DBEEF; address_type warp_next_pc = 0x600DBEEF; int warp_diverging = 0; - const int nextstage = (gpgpu_operand_collector) ? ID_OC : \ - (shader->using_rrstage ? ID_RR : ID_EX); - unsigned warp_id = -1; - unsigned cta_id = -1; + const int nextstage = (m_config->gpgpu_operand_collector) ? ID_OC : \ + (m_config->m_using_dwf_rrstage ? ID_RR : ID_EX); - // stalling for register bank conflict - if ( gpgpu_reg_bank_conflict_model ) { - for (i=0; i<pipe_simd_width;i++) { - if ( shader->pipeline_reg[IF_ID][i].reg_bank_conflict_stall_checked ) { - if ( shader->pipeline_reg[IF_ID][i].reg_bank_access_pending > 0 ) { - assert( shader->pipeline_reg[IF_ID][i].reg_bank_access_pending <= 8 ); - shader->pipeline_reg[IF_ID][i].reg_bank_access_pending--; - gpu_reg_bank_conflict_stalls++; - return; - } - } - } - } - - for (i=0; i<pipe_simd_width;i++) { - if (shader->pipeline_reg[nextstage][i].hw_thread_id != -1 ) { - return; /* stalled */ - } - } + if( !pipeline_regster_empty(m_pipeline_reg[nextstage]) ) + return; - check_stage_pcs(shader,IF_ID); + check_stage_pcs(IF_ID); // decode the instruction int first_valid_thread = -1; - for (i=0; i<pipe_simd_width;i++) { - - if (shader->pipeline_reg[IF_ID][i].hw_thread_id == -1 ) - continue; /* bubble */ - - /* get the next instruction to execute from fetch stage */ - tid = shader->pipeline_reg[IF_ID][i].hw_thread_id; + for (unsigned i=0; i<m_config->warp_size;i++) { + if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 ) + continue; /* bubble or masked off */ if (first_valid_thread == -1) { first_valid_thread = i; - warp_id = tid/warp_size; - assert( !shader->warp_waiting_at_barrier(warp_id) ); - cta_id = shader->thread[tid].cta_id; - } - - if ( gpgpu_cuda_sim ) { - ptx_decode_inst( shader->thread[tid].ptx_thd_info, (unsigned*)&op, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg, &pred, &ar1, &ar2); - shader->pipeline_reg[IF_ID][i].op = op; - shader->pipeline_reg[IF_ID][i].pc = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info ); - shader->pipeline_reg[IF_ID][i].ptx_thd_info = shader->thread[tid].ptx_thd_info; - - } else { - abort(); - } - // put the info into the shader instruction structure - // - useful in tracking instruction dependency (not needed for now) - shader->pipeline_reg[IF_ID][i].in[0] = i1; - shader->pipeline_reg[IF_ID][i].in[1] = i2; - shader->pipeline_reg[IF_ID][i].in[2] = i3; - shader->pipeline_reg[IF_ID][i].in[3] = i4; - shader->pipeline_reg[IF_ID][i].out[0] = o1; - shader->pipeline_reg[IF_ID][i].out[1] = o2; - shader->pipeline_reg[IF_ID][i].out[2] = o3; - shader->pipeline_reg[IF_ID][i].out[3] = o4; - - } - - // checking for register bank conflict and stall accordingly - if ( gpgpu_reg_bank_conflict_model && - first_valid_thread != -1 && - !shader->pipeline_reg[first_valid_thread][IF_ID].reg_bank_conflict_stall_checked ) - { - for (i = 4; i < 8; i++) { - if( arch_reg[i] != -1 ) { - assert( arch_reg[i] >=0 ); - assert( gpgpu_num_reg_banks <= MAX_REG_BANKS ); - int skip = 0; - int bank = arch_reg[i] % gpgpu_num_reg_banks; - int opndreg = shader->pipeline_reg[first_valid_thread][IF_ID].in[i-4]; - assert(opndreg >= 0); - int j; - for (j = 0; j < 4; j++) { - if (g_reg_bank_access[bank].rd_regs[j] == -1) - break; - else if (g_reg_bank_access[bank].rd_regs[j] == opndreg) { - // two operands reading from same register in same bank, can be merged into a single read - skip = 1; - break; - } - } - if (!skip) { - g_reg_bank_access[bank].tot++; - g_reg_bank_access[bank].rd++; - g_reg_bank_access[bank].rd_regs[j] = opndreg; - } - } - } - - unsigned max_access=0; - inst_t* conflict_inst = &shader->pipeline_reg[first_valid_thread][IF_ID]; - for(unsigned r = 0; r < gpgpu_num_reg_banks; r++ ) { - if( g_reg_bank_access[r].tot > max_access ) - max_access = g_reg_bank_access[r].tot; - g_reg_bank_access[r] = empty_reg_bank_access; - } - if( max_access >= 1 ) { - assert( max_access <= MAX_REG_OPERANDS ); - conflict_inst->reg_bank_access_pending = max_access - 1; - if( max_access > 1 ) { - conflict_inst->reg_bank_conflict_stall_checked = 1; - return; // stall pipeline - } - } - shader->pipeline_reg[first_valid_thread][IF_ID].reg_bank_conflict_stall_checked = 1; + op = m_pipeline_reg[IF_ID][i].op; + int tid = m_pipeline_reg[IF_ID][i].hw_thread_id; + warp_id = tid/m_config->warp_size; + assert( !warp_waiting_at_barrier(warp_id) ); + cta_id = m_thread[tid].m_cta_id; + } } // execute the instruction functionally short last_hw_thread_id = -1; bool first_thread_in_warp = true; - for (i=0; i<pipe_simd_width;i++) { - if (shader->pipeline_reg[IF_ID][i].hw_thread_id == -1 ) - continue; /* bubble */ + for (unsigned i=0; i<m_config->warp_size;i++) { + if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 ) + continue; /* bubble or masked off */ if(last_hw_thread_id > -1) first_thread_in_warp = false; - last_hw_thread_id = shader->pipeline_reg[IF_ID][i].hw_thread_id; + last_hw_thread_id = m_pipeline_reg[IF_ID][i].hw_thread_id; /* get the next instruction to execute from fetch stage */ - tid = shader->pipeline_reg[IF_ID][i].hw_thread_id; - if ( gpgpu_cuda_sim ) { - int arch_reg[MAX_REG_OPERANDS]; - - // Decode instruction - ptx_decode_inst( shader->thread[tid].ptx_thd_info, (unsigned*)&op, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg, &pred, &ar1, &ar2 ); - - // Functionally execute instruction - ptx_exec_inst( shader->thread[tid].ptx_thd_info, &addr, &space, &data_size, &cycles, &callback, shader->pipeline_reg[IF_ID][i].warp_active_mask ); - - shader->pipeline_reg[IF_ID][i].callback = callback; - shader->pipeline_reg[IF_ID][i].space = space; - if (is_local(space) && (is_load(op) || is_store(op))) { - addr = translate_local_memaddr(addr, shader, tid); - } - shader->pipeline_reg[IF_ID][i].is_vectorin = vectorin; - shader->pipeline_reg[IF_ID][i].is_vectorout = vectorout; - shader->pipeline_reg[IF_ID][i].pred = pred; - shader->pipeline_reg[IF_ID][i].ar1 = ar1; - shader->pipeline_reg[IF_ID][i].ar2 = ar2; - shader->pipeline_reg[IF_ID][i].data_size = data_size; - shader->pipeline_reg[IF_ID][i].cycles = cycles; - - // Mark destination registers as write-pending in scoreboard - // Only do this for the first thread in warp - if(first_thread_in_warp) { - shader->scrb->reserveRegisters(warp_id, &(shader->pipeline_reg[IF_ID][i])); - //shader->scrb->printContents(); - } + int tid = m_pipeline_reg[IF_ID][i].hw_thread_id; - warp_current_pc = shader->pipeline_reg[IF_ID][i].pc; - memcpy( shader->pipeline_reg[IF_ID][i].arch_reg, arch_reg, sizeof(arch_reg) ); - regs_regs_PC = ptx_thread_get_next_pc( shader->thread[tid].ptx_thd_info ); - } + // Functionally execute instruction + m_thread[tid].m_functional_model_thread_state->ptx_exec_inst( m_pipeline_reg[IF_ID][i] ); + if( m_pipeline_reg[IF_ID][i].callback.function != NULL ) + m_warp[warp_id].inc_n_atomic(); + if (is_local(m_pipeline_reg[IF_ID][i].space) && (is_load(m_pipeline_reg[IF_ID][i]) || is_store(m_pipeline_reg[IF_ID][i]))) + m_pipeline_reg[IF_ID][i].memreqaddr = translate_local_memaddr(m_pipeline_reg[IF_ID][i].memreqaddr, tid, m_gpu->num_shader()); - shader->pipeline_reg[IF_ID][i].memreqaddr = addr; - if ( op == LOAD_OP ) { - shader->pipeline_reg[IF_ID][i].inst_type = LOAD_OP; - } else if ( op == STORE_OP ) { - shader->pipeline_reg[IF_ID][i].inst_type = STORE_OP; - } + // Mark destination registers as write-pending in scoreboard + // Only do this for the first thread in warp + if(first_thread_in_warp) + m_scoreboard->reserveRegisters(warp_id, &(m_pipeline_reg[IF_ID][i])); + warp_current_pc = m_pipeline_reg[IF_ID][i].pc; + regs_regs_PC = next_pc( tid ); - if ( gpgpu_cuda_sim && ptx_thread_at_barrier( shader->thread[tid].ptx_thd_info ) ) { - if (shader->model == DWF) { - shader->thread[tid].m_waiting_at_barrier=1; - shader->thread[tid].m_reached_barrier=1; // not reset at barrier release, but at the issue after that - shader->warp[wid_from_hw_tid(tid,warp_size)].n_waiting_at_barrier++; - shader->waiting_at_barrier++; - int cta_uid = ptx_thread_get_cta_uid( shader->thread[tid].ptx_thd_info ); - dwf_hit_barrier( shader->sid, cta_uid ); + if ( ptx_thread_at_barrier( m_thread[tid].m_functional_model_thread_state ) ) { + if (m_config->model == DWF) { + m_thread[tid].m_waiting_at_barrier=true; + m_thread[tid].m_reached_barrier=true; // not reset at barrier release, but at the issue after that + m_warp[wid_from_hw_tid(tid,m_config->warp_size)].inc_waiting_at_barrier(); + int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state ); + dwf_hit_barrier( m_sid, cta_uid ); - int release = ptx_thread_all_at_barrier( shader->thread[tid].ptx_thd_info ); //test if all threads arrived at the barrier + int release = ptx_thread_all_at_barrier( m_thread[tid].m_functional_model_thread_state ); //test if all threads arrived at the barrier if ( release ) { //All threads arrived at barrier...releasing - int cta_uid = ptx_thread_get_cta_uid( shader->thread[tid].ptx_thd_info ); - for ( unsigned t=0; t < gpu_n_thread_per_shader; ++t ) { - if ( !ptx_thread_at_barrier( shader->thread[t].ptx_thd_info ) ) + int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state ); + for ( unsigned t=0; t < m_config->n_thread_per_shader; ++t ) { + if ( !ptx_thread_at_barrier( m_thread[t].m_functional_model_thread_state ) ) continue; - int other_cta_uid = ptx_thread_get_cta_uid( shader->thread[t].ptx_thd_info ); + int other_cta_uid = ptx_thread_get_cta_uid( m_thread[t].m_functional_model_thread_state ); if ( other_cta_uid == cta_uid ) { //reseting @barrier tracking info - shader->warp[wid_from_hw_tid(t,warp_size)].n_waiting_at_barrier=0; - shader->thread[t].m_waiting_at_barrier=0; - ptx_thread_reset_barrier( shader->thread[t].ptx_thd_info ); - shader->waiting_at_barrier--; + m_warp[wid_from_hw_tid(t,m_config->warp_size)].clear_waiting_at_barrier(); + m_thread[t].m_waiting_at_barrier=false; + ptx_thread_reset_barrier( m_thread[t].m_functional_model_thread_state ); } } - if (shader->model == DWF) { - dwf_release_barrier( shader->sid, cta_uid ); + if (m_config->model == DWF) { + dwf_release_barrier( m_sid, cta_uid ); } - ptx_thread_release_barrier( shader->thread[tid].ptx_thd_info ); + ptx_thread_release_barrier( m_thread[tid].m_functional_model_thread_state ); } } } else { - assert( !shader->thread[tid].m_waiting_at_barrier ); + assert( !m_thread[tid].m_waiting_at_barrier ); } - // put the info into the shader instruction structure - // - useful in tracking instruction dependency (not needed for now) - shader->pipeline_reg[IF_ID][i].in[0] = i1; - shader->pipeline_reg[IF_ID][i].in[1] = i2; - shader->pipeline_reg[IF_ID][i].in[2] = i3; - shader->pipeline_reg[IF_ID][i].in[3] = i4; - shader->pipeline_reg[IF_ID][i].out[0] = o1; - shader->pipeline_reg[IF_ID][i].out[1] = o2; - shader->pipeline_reg[IF_ID][i].out[2] = o3; - shader->pipeline_reg[IF_ID][i].out[3] = o4; - - // go to the next instruction - // - done implicitly in ptx_exec_inst() - // branch divergence detection if (warp_next_pc != regs_regs_PC) { if (warp_next_pc == 0x600DBEEF) { @@ -2003,21 +1528,16 @@ void shader_decode( shader_core_ctx_t *shader, warp_diverging = 1; } } - - // direct the instruction to the appropriate next stage (config dependent) - shader->pipeline_reg[nextstage][i] = shader->pipeline_reg[IF_ID][i]; - shader->pipeline_reg[nextstage][i].id_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - shader->pipeline_reg[IF_ID][i] = nop_inst; } - if( op == BARRIER_OP ) { - shader->set_at_barrier(cta_id,warp_id); - } + move_warp(m_pipeline_reg[nextstage],m_pipeline_reg[IF_ID]); - if ( shader->model == NO_RECONVERGE && touched_priority ) { - update_max_branch_priority(shader,warp_tid,grid_num); - } - shader->n_diverge += warp_diverging; + if( op == BARRIER_OP ) + set_at_barrier(cta_id,warp_id); + else if( op == MEMORY_BARRIER_OP ) + set_at_memory_barrier(warp_id); + + m_n_diverge += warp_diverging; if (warp_diverging == 1) { assert(warp_current_pc != 0x600DBEEF); // guard against empty warp causing warp divergence ptx_file_line_stats_add_warp_divergence(warp_current_pc, 1); @@ -2036,451 +1556,381 @@ int regfile_hash(signed thread_number, unsigned simd_size, unsigned n_banks) { } } -int gpgpu_n_reg_banks = 8; -void shader_preexecute( shader_core_ctx_t *shader, - unsigned int shader_number ) { - int i; - static int *thread_warp = NULL; - int n_access_per_cycle = pipe_simd_width / gpgpu_n_reg_banks; - - if (!thread_warp) { - thread_warp = (int*) malloc(sizeof(int) * pipe_simd_width); - } +void shader_core_ctx::preexecute() +{ + if( m_config->gpgpu_dwf_reg_bankconflict) { + // Model register bank conflicts as in + // Fung et al. MICRO'07 / ACM TACO'09 papers. + // + // This models conflicts due to moving threads to different SIMD lanes + // (which occur if not using "lane aware" dynamic warp formation). - for (i=0; i<pipe_simd_width; i++) { - if (shader->pipeline_reg[RR_EX][i].hw_thread_id != -1 ) { - //stalled, but can still service a register read - if (shader->RR_k) { - shader->RR_k--; + inst_t *fvi = first_valid_thread(m_pipeline_reg[RR_EX]); + if( fvi ) { + if (m_dwf_RR_k) { + //stalled due to register access conflict, but can still service a register read + m_dwf_RR_k--; + return; } - return; // stalled - } - } - - // if there is still register read to service, stall - if (shader->RR_k > 1) { - shader->RR_k--; - return; - } - - // if RR_k == 1, it was stalled previously and the register read is now done - if (!shader->RR_k && gpgpu_reg_bankconflict) { - int max_reg_bank_acc = 0; - for (i=0; i<pipe_simd_width; i++) { - thread_warp[i] = 0; - } - for (i=0; i<pipe_simd_width; i++) { - if (shader->pipeline_reg[ID_RR][i].hw_thread_id != -1 ) - thread_warp[regfile_hash(shader->pipeline_reg[ID_RR][i].hw_thread_id, - warp_size, gpgpu_n_reg_banks)]++; - } - for (i=0; i<pipe_simd_width; i++) { - if (thread_warp[i] > max_reg_bank_acc ) { - max_reg_bank_acc = thread_warp[i]; + + int n_access_per_cycle = m_config->warp_size / m_config->gpgpu_dwf_rr_stage_n_reg_banks; + int max_reg_bank_acc = 0; + for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++) + m_dwf_rrstage_bank_access_counter[i] = 0; + for (unsigned i=0; i<m_config->warp_size; i++) { + if (m_pipeline_reg[ID_RR][i].hw_thread_id != -1 ) + m_dwf_rrstage_bank_access_counter[regfile_hash(m_pipeline_reg[ID_RR][i].hw_thread_id, + m_config->warp_size, + m_config->gpgpu_dwf_rr_stage_n_reg_banks)]++; + } + for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++) { + if (m_dwf_rrstage_bank_access_counter[i] > max_reg_bank_acc ) + max_reg_bank_acc = m_dwf_rrstage_bank_access_counter[i]; + } + // calculate the number of cycles needed for each register bank to fulfill all accesses + m_dwf_RR_k = (max_reg_bank_acc / n_access_per_cycle) + ((max_reg_bank_acc % n_access_per_cycle)? 1 : 0); + + // if there is more than one access cycle needed at a bank, stall + if (m_dwf_RR_k > 1) { + n_regconflict_stall++; + m_dwf_RR_k--; + return; } } - // calculate the number of cycles needed for each register bank to fulfill all accesses - shader->RR_k = (max_reg_bank_acc / n_access_per_cycle) + ((max_reg_bank_acc % n_access_per_cycle)? 1 : 0); - } - - // if there are more than one access cycle needed at a bank, stall - if (shader->RR_k > 1) { - n_regconflict_stall++; - shader->RR_k--; - return; - } - - check_stage_pcs(shader,ID_RR); - - shader->RR_k = 0; //setting RR_k to 0 to indicate RF conflict check next cycle - for (i=0; i<pipe_simd_width;i++) { - if (shader->pipeline_reg[ID_RR][i].hw_thread_id == -1 ) - continue; //bubble - shader->pipeline_reg[ID_EX][i] = shader->pipeline_reg[ID_RR][i]; - shader->pipeline_reg[ID_RR][i] = nop_inst; + + check_stage_pcs(ID_RR); + m_dwf_RR_k = 0; } + if( pipeline_regster_empty(m_pipeline_reg[ID_EX]) ) + move_warp(m_pipeline_reg[ID_EX],m_pipeline_reg[ID_RR]); } -void shader_execute_pipe( shader_core_ctx_t *shader, unsigned int shader_number, unsigned pipeline, unsigned next_stage ) +void shader_core_ctx::execute_pipe( unsigned pipeline, unsigned next_stage ) { - int i; - for (i=0; i<pipe_simd_width; i++) { - if (gpgpu_pre_mem_stages) { - if (shader->pre_mem_pipeline[0][i].hw_thread_id != -1 ) { - return; // stalled - } - } else { - if (shader->pipeline_reg[next_stage][i].hw_thread_id != -1 ) - return; // stalled - } + if (m_config->gpgpu_pre_mem_stages) { + if( !pipeline_regster_empty(pre_mem_pipeline[0]) ) + return; // stalled + } else { + if( !pipeline_regster_empty(m_pipeline_reg[next_stage]) ) + return; // stalled } - - check_stage_pcs(shader,ID_EX); + + check_stage_pcs(ID_EX); // Check that all threads have the same delay cycles unsigned cycles = -1; - for (i=0; i<pipe_simd_width; i++) { - if (shader->pipeline_reg[pipeline][i].hw_thread_id == -1 ) + for (unsigned i=0; i<m_config->warp_size; i++) { + if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 ) continue; // bubble if(cycles == (unsigned)-1) - cycles = shader->pipeline_reg[pipeline][i].cycles; + cycles = m_pipeline_reg[pipeline][i].cycles; else { - if( cycles != shader->pipeline_reg[pipeline][i].cycles ) { - printf("Shader %d: threads do not have the same delay cycles.\n", shader->sid); + if( cycles != m_pipeline_reg[pipeline][i].cycles ) { + printf("Shader %d: threads do not have the same delay cycles.\n", m_sid); assert(0); } } } - for (i=0; i<pipe_simd_width; i++) { - if (shader->pipeline_reg[pipeline][i].hw_thread_id == -1 ) - continue; // bubble - - // Stall based on delay cycles - shader->pipeline_reg[pipeline][i].cycles--; - if( shader->pipeline_reg[pipeline][i].cycles > 0 ) + bool stall_inst_not_done = false; + for (unsigned i=0; i<m_config->warp_size; i++) { + if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 ) + continue; + m_pipeline_reg[pipeline][i].cycles--; + if( m_pipeline_reg[pipeline][i].cycles > 0 ) { + // Stall here to model instruction throughput for different types of instructions + stall_inst_not_done=true; continue; - - if (gpgpu_pre_mem_stages) { - shader->pre_mem_pipeline[0][i] = shader->pipeline_reg[pipeline][i]; - shader->pre_mem_pipeline[0][i].ex_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - } else { - shader->pipeline_reg[next_stage][i] = shader->pipeline_reg[pipeline][i]; - shader->pipeline_reg[next_stage][i].ex_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; } - shader->pipeline_reg[pipeline][i] = nop_inst; - } - - if (!gpgpu_pre_mem_stages) { + } + if( stall_inst_not_done ) + return; + if (m_config->gpgpu_pre_mem_stages) { + move_warp(pre_mem_pipeline[0], m_pipeline_reg[pipeline]); + } else { + move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]); // inform memory stage that a new instruction has arrived - shader->shader_memory_new_instruction_processed = 0; + m_shader_memory_new_instruction_processed = false; } } -void shader_execute( shader_core_ctx_t *shader, unsigned int shader_number ) +void shader_core_ctx::execute() { - shader_execute_pipe(shader,shader_number, OC_EX_SFU, EX_MM); - shader_execute_pipe(shader,shader_number, ID_EX, EX_MM); + execute_pipe(OC_EX_SFU, EX_MM); + execute_pipe(ID_EX, EX_MM); } -void shader_pre_memory( shader_core_ctx_t *shader, - unsigned int shader_number ) { - int i,j; - - - for (j = gpgpu_pre_mem_stages; j > 0; j--) { - for (i=0; i<pipe_simd_width; i++) { - if (shader->pre_mem_pipeline[j][i].hw_thread_id != -1 ) { - return; - } - } - check_pm_stage_pcs(shader,j-1); - for (i=0; i<pipe_simd_width; i++) { - shader->pre_mem_pipeline[j][i] = shader->pre_mem_pipeline[j - 1][i]; - shader->pre_mem_pipeline[j - 1][i] = nop_inst; - } +void shader_core_ctx::pre_memory() +{ + // This stage can be used to approximately model a deeper pipeline. + // The main effect this models is the register read-after-write delay. + // We walk through pre-memory stages in reverse order + // (highest number = stage closest to writeback, 0 = stage closest to fetch + if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) ) { + move_warp( m_pipeline_reg[EX_MM], pre_mem_pipeline[m_config->gpgpu_pre_mem_stages] ); + // inform memory stage that a new instruction has arrived + m_shader_memory_new_instruction_processed = false; } - check_pm_stage_pcs(shader,gpgpu_pre_mem_stages); - for (i=0;i<pipe_simd_width ;i++ ) - shader->pipeline_reg[EX_MM][i] = shader->pre_mem_pipeline[gpgpu_pre_mem_stages][i]; - - // inform memory stage that a new instruction has arrived - shader->shader_memory_new_instruction_processed = 0; - - if (gpgpu_pre_mem_stages) { - for (i=0; i<pipe_simd_width; i++) - shader->pre_mem_pipeline[0][i] = nop_inst; + for (unsigned j = m_config->gpgpu_pre_mem_stages; j > 0; j--) { + if( pipeline_regster_empty(pre_mem_pipeline[j]) ) + move_warp( pre_mem_pipeline[j], pre_mem_pipeline[j-1]); } } -int gpgpu_coalesce_arch; - -enum memory_path { - NO_MEM_PATH = 0, - SHARED_MEM_PATH, - GLOBAL_MEM_PATH, - TEXTURE_MEM_PATH, - CONSTANT_MEM_PATH, - NUM_MEM_PATHS //not a mem path -}; - -static unsigned next_access_uid = 0; - -class mem_access_t{ -public: - mem_access_t(): uid(next_access_uid++),addr(0),req_size(0),order(0),_quarter_count_all(0),warp_indices(),space(undefined_space),path(NO_MEM_PATH),isatomic(false),cache_hit(false),cache_checked(false),recheck_cache(false),iswrite(false),need_wb(false),wb_addr(0),reserved_mshr(NULL){}; - bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse - unsigned uid; - address_type addr; //address of the segment to load. - unsigned req_size; //bytes - unsigned order; // order of accesses, based on banks. - union{ - unsigned _quarter_count_all; - char quarter_count[4]; //access counts to each quarter of segment, for compaction; - }; - std::vector<unsigned> warp_indices; //warp indicies for this request. - memory_space_t space; - memory_path path; - bool isatomic; - bool cache_hit; - bool cache_checked; - bool recheck_cache; - bool iswrite; - bool need_wb; - address_type wb_addr; //address to wb too if necessary. - mshr_entry_t* reserved_mshr; -}; - -mshr_entry_t* mshr_shader_unit::add_mshr(mem_access_t &access, inst_t* warp) +mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, inst_t* warp) { - static unsigned next_request_uid = 1; - mshr_entry_t* mshr = alloc_free_mshr(is_tex(access.space)); - //note no constructor was called, all entries must be reinitialized! - mshr->request_uid = next_request_uid++; - mshr->status = INITIALIZED; - mshr->addr = access.addr; - mshr->mf = NULL; - mshr->merged_on_other_reqest = false; - mshr->merged_requests =NULL; - mshr->iswrite = access.iswrite; - assert(access.warp_indices.size()); //code assumes at least one instruction attached to mshr. - for (unsigned i = 0; i < access.warp_indices.size(); i++) { - mshr->insts.push_back(warp[access.warp_indices[i]]); - } - mshr->islocal = is_local(access.space); - mshr->isconst = is_const(access.space); - mshr->istexture = is_tex(access.space); - if (gpgpu_interwarp_mshr_merge) { - mshr_entry_t* mergehit = m_mshr_lookup.shader_get_mergeable_mshr(mshr); - if (mergehit) { - //merge this request; - mergehit->merged_requests = mshr; - mshr->merged_on_other_reqest = true; - if (mergehit->fetched()) mshr_return_from_mem(mshr); - } - m_mshr_lookup.mshr_fast_lookup_insert(mshr); - } - return mshr; + //creates an mshr based on the access struct information + mshr_entry* mshr = alloc_free_mshr(access.space == tex_space); + mshr->init(access.addr,access.iswrite,access.space,warp->hw_thread_id/m_shader_config->warp_size); + assert(access.warp_indices.size()); //code assumes at least one instruction attached to mshr. + for (unsigned i = 0; i < access.warp_indices.size(); i++) + mshr->add_inst(warp[access.warp_indices[i]]); + if (m_shader_config->gpgpu_interwarp_mshr_merge) { + mshr_entry* mergehit = m_mshr_lookup.shader_get_mergeable_mshr(mshr); + if (mergehit) { + mergehit->merge(mshr); + if (mergehit->fetched()) + mshr_return_from_mem(mshr); + } + m_mshr_lookup.mshr_fast_lookup_insert(mshr); + } + return mshr; } - -inline address_type line_size_based_tag_func(address_type address, unsigned line_size) +address_type line_size_based_tag_func(address_type address, unsigned line_size) { + //gives the tag for an address based on a given line size return ((address) & (~((address_type)line_size - 1))); } -inline address_type null_tag_func(address_type address, unsigned line_size){ +address_type null_tag_func(address_type address, unsigned line_size) +{ return address; //no modification: each address is its own tag. Equivalent to line_size_based_tag_func(address,1), but line_size ignored. } // only 1 bank -inline int null_bank_func(address_type add, unsigned line_size) +int shader_core_ctx::null_bank_func(address_type add, unsigned line_size) { return 1; } -inline int shmem_bank_func(address_type add, unsigned line_size) +int shader_core_ctx::shmem_bank_func(address_type addr, unsigned line_size) { - return shmem_bank(add); + //returns the integer number of the physical bank addr would go in. + return ((int)(addr/((address_type)WORD_SIZE)) % m_config->gpgpu_n_shmem_bank); } -inline int dcache_bank_func(address_type add, unsigned line_size) +int shader_core_ctx::dcache_bank_func(address_type add, unsigned line_size) { - if (gpgpu_no_dl1) return 1; //no banks - else return (add / line_size) & (gpgpu_n_cache_bank - 1); + //returns the integer number of the physical bank addr would go in. + if (m_config->gpgpu_no_dl1) return 1; //no banks + else return (add / line_size) & (m_config->gpgpu_n_cache_bank - 1); } -#include <bitset> -void check_accessq( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq ){ - std::bitset<32> check = 0; - for (unsigned i = 0; i < accessq.size(); i++) { - if (shader) { - std::cout << shader->sid << ":" << i << " space " << accessq[i].space.get_type() << " " << gpu_sim_cycle << std::endl; - assert(accessq[i].space == shader->pipeline_reg[EX_MM][accessq[i].warp_indices[0]].space); - } - for (unsigned j = 0; j < accessq[i].warp_indices.size(); j++) { - if (check[accessq[i].warp_indices[j]]) { - std::cout << "OOOPS" << std::endl; //good line for breakpoint - }else{check[accessq[i].warp_indices[j]] = true;} - } - } -} +typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size); +typedef address_type (*tag_func_t)(address_type add, unsigned line_size); -// This speciallized function calculates the list of independant memory accesses, sorted by access order -// Acesses to same tag line are coalesced. -// will neither coalesce nor overlap bank accesses accross warp parts. -template < int (*bank_func)(address_type add, unsigned line_size), address_type (*tag_func)(address_type add, unsigned line_size) > -inline void get_memory_access_list(inst_t* insns, unsigned char* paths, memory_path path, unsigned warp_parts, unsigned line_size, bool limit_broadcast,std::vector<mem_access_t> &accessq) +void shader_core_ctx::get_memory_access_list( + shader_core_ctx::bank_func_t bank_func, + tag_func_t tag_func, + memory_pipe_t mem_pipe, + unsigned warp_parts, + unsigned line_size, + bool limit_broadcast, + std::vector<mem_access_t> &accessq ) { - // calculates the memory accesses for a generic cache with banks and tags. - // can be used for coalesescing + const inst_t* insns = m_pipeline_reg[EX_MM]; + // Calculates memory accesses generated by this warp + // Returns acesses which are "coalesced" + // Does not coalesce nor overlap bank accesses across warp "parts". - //tracks bank accesses for sorting into generations; - static std::map<unsigned,unsigned> bank_accs; - bank_accs.clear(); - //keep track of broadcasts with unique orders if limit_broadcast - //the normally calculated orders will never be greater than pipe_simd_width; - unsigned broadcast_order = pipe_simd_width; + // This is called once per warp when it enters the memory stage. + // It takes the warp and produces a queue of accesses that can be peformed. + // These are then performed over multiple cycles (stalling the pipeline) if the accessses cannot be + // performed all at once. + // It is a convenience for simulation; in hardware the warp would be processed each cycle + // until it was done. Each cycle would do the first accesses available to it and mark off the + // those threads served by those accesses. + + // Because it calculates all the accesses at once, what follows is largely not as the hw would do it. + // Accesses are assigned an order number based on when that access may be issued. + // Accesses with the same order number may occur at the same time: they are to different banks. + // Later when the queue is processed it will evaluate accesses of + // as many orders as ports on that cache/shmem. + // These accesses are placed into a queue and sorted so that accesses of the same order are next to each other. + + + // tracks bank accesses for sorting into generations; + // each entry is (bank #, number of accesses) + // the idea is that you can only access a bank a number of times each cycle equal to + // its number of ports in one cycle. + std::map<unsigned,unsigned> bank_accs; + + //keep track of broadcasts with unique orders if limit_broadcast + //the normally calculated orders will never be greater than warp_size + unsigned broadcast_order = m_config->warp_size; unsigned qbegin = accessq.size(); unsigned qpartbegin = qbegin; - unsigned mem_pipe_size = pipe_simd_width / warp_parts; - for (unsigned part = 0; part < (unsigned)pipe_simd_width; part += mem_pipe_size) { + unsigned mem_pipe_size = m_config->warp_size / warp_parts; + for (unsigned part = 0; part < m_config->warp_size; part += mem_pipe_size) { for (unsigned i = part; i < part + mem_pipe_size; i++) { - if (paths[i] != path) continue; //skip instructions from other memory paths - address_type segment = (*tag_func)(insns[i].memreqaddr, line_size); - unsigned quarter=0; - if ( line_size>=4 ) { - quarter = (insns[i].memreqaddr / (line_size/4)) & 3; - } - //check if we are already loading this segment. + if ( insns[i].hw_thread_id == -1 ) + continue; + + if( insns[i].space == undefined_space ) { + // Instruction must have been predicated off + continue; + } + + address_type lane_segment_address = tag_func(insns[i].memreqaddr, line_size); + unsigned quarter = 0; + if( line_size>=4 ) + quarter = (insns[i].memreqaddr / (line_size/4)) & 3; bool isatomic = (insns[i].callback.function != NULL); - unsigned match = 0; + bool match = false; if (not isatomic) { //atomics must have own request for (unsigned j = qpartbegin; j < accessq.size(); j++) { - if (segment == accessq[j].addr and not accessq[j].isatomic) { - //match + if (lane_segment_address == accessq[j].addr) { + assert( not accessq[j].isatomic ); accessq[j].quarter_count[quarter]++; accessq[j].warp_indices.push_back(i); - if (limit_broadcast) accessq[j].order = ++broadcast_order; //do proadcast in its own cycle. - match = 1; + if (limit_broadcast) + // two threads access this address, so its a broadcast. + accessq[j].order = ++broadcast_order; //do broadcast in its own cycle. + match = true; break; } } } - if (!match) { - //needs its own request - accessq.push_back(mem_access_t()); - accessq.back().addr = segment; - accessq.back().space = insns[i].space; - accessq.back().path = path; - accessq.back().isatomic = isatomic; - accessq.back().iswrite = is_store(insns[i].op); - accessq.back().req_size = line_size; - accessq.back().quarter_count[quarter]++; - accessq.back().warp_indices.push_back(i); - - //Determine Bank Conflicts. - unsigned bank = (*bank_func)(insns[i].memreqaddr, line_size); - //ensure no concurrent bank access accross warp parts. + if (!match) { // does not match an previous request by another thread, so need a new request + assert( insns[i].space != undefined_space ); + accessq.push_back( mem_access_t( lane_segment_address, + insns[i].space, + mem_pipe, + isatomic, + is_store(insns[i]), + line_size, quarter, i) ); + // Determine Bank Conflicts: + unsigned bank = (this->*bank_func)(insns[i].memreqaddr, line_size); + // ensure no concurrent bank access accross warp parts. // ie. order will be less than part for all previous loads in previous parts, so: - if (bank_accs[bank] < part) bank_accs[bank]=part; + if (bank_accs[bank] < part) + bank_accs[bank]=part; accessq.back().order = bank_accs[bank]; bank_accs[bank]++; } } qpartbegin = accessq.size(); //don't coalesce accross warp parts } - //sort requests into order accorting to order (orders will not necessarily be consequtive if multiple parts) - std::stable_sort(accessq.begin()+qbegin,accessq.end()); //this is a reverse sort, least order last, but doesn't really matter where consumed. -} + //sort requests into order according to order (orders will not necessarily be consequtive if multiple parts) + std::stable_sort(accessq.begin()+qbegin,accessq.end()); +} -void shader_memory_shared_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq) +void shader_core_ctx::memory_shared_process_warp() { - get_memory_access_list<&shmem_bank_func, &null_tag_func>(shader->pipeline_reg[EX_MM], paths, SHARED_MEM_PATH, - gpgpu_shmem_pipe_speedup, + // initial processing of shared memory warps + get_memory_access_list(&shader_core_ctx::shmem_bank_func, + null_tag_func, + SHARED_MEM_PATH, + m_config->gpgpu_shmem_pipe_speedup, 1, //shared memory doesn't care about line_size, needs to be at least 1; - true, //limit broadcasts to single cycle. - accessq); - //thats it :) + true, // limit broadcasts to single cycle. + m_memory_queue.shared); } -void shader_memory_const_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq) +void shader_core_ctx::memory_const_process_warp() { + // initial processing of const memory warps + std::vector<mem_access_t> &accessq = m_memory_queue.constant; unsigned qbegin = accessq.size(); - get_memory_access_list<&null_bank_func, &line_size_based_tag_func>(shader->pipeline_reg[EX_MM], paths, CONSTANT_MEM_PATH, - 1, //warp parts - shader->L1constcache->line_sz, - false, //no broadcast limit. - accessq); - //do cache checks here for each request, could be done later for more accurate timing of cache accesses, but probably uneccesary; + get_memory_access_list( + &shader_core_ctx::null_bank_func, + line_size_based_tag_func, + CONSTANT_MEM_PATH, + 1, //warp parts + m_L1C->line_sz, false, //no broadcast limit. + accessq); + //do cache checks here for each request (non-physical), could be done later for more accurate timing of cache accesses, but probably uneccesary; for (unsigned i = qbegin; i < accessq.size(); i++) { - if (is_param(accessq[i].space)) { + if ( accessq[i].space == param_space_kernel ) { accessq[i].cache_hit = true; } else { - cache_request_status status = shd_cache_access_wb(shader->L1constcache, + cache_request_status status = shd_cache_access_new(m_L1C, accessq[i].addr, WORD_SIZE, //this field is ingored. 0, //should always be a read - shader->gpu_cycle, + gpu_sim_cycle+gpu_tot_sim_cycle, NULL/*should never writeback*/); accessq[i].cache_hit = (status == HIT); - if (gpgpu_perfect_mem) accessq[i].cache_hit = true; - if (accessq[i].cache_hit) L1_const_miss++; + if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; + if (accessq[i].cache_hit) m_stats->L1_const_miss++; } accessq[i].cache_checked = true; } } -void shader_memory_texture_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq) +void shader_core_ctx::memory_texture_process_warp() { + // initial processing of shared texture warps + std::vector<mem_access_t> &accessq = m_memory_queue.texture; unsigned qbegin = accessq.size(); - get_memory_access_list<&null_bank_func, &line_size_based_tag_func>(shader->pipeline_reg[EX_MM], paths, TEXTURE_MEM_PATH, + get_memory_access_list(&shader_core_ctx::null_bank_func, + &line_size_based_tag_func, + TEXTURE_MEM_PATH, 1, //warp parts - shader->L1texcache->line_sz, + m_L1T->line_sz, false, //no broadcast limit. accessq); - //do cache checks here for each request, could be done later for more accurate timing of cache accesses, but probably uneccesary; + //do cache checks here for each request (non-hardware), could be done later for more accurate timing of cache accesses, but probably uneccesary; for (unsigned i = qbegin; i < accessq.size(); i++) { - cache_request_status status = shd_cache_access_wb(shader->L1texcache, + cache_request_status status = shd_cache_access_new(m_L1T, accessq[i].addr, WORD_SIZE, //this field is ignored. 0, //should always be a read - shader->gpu_cycle, + gpu_sim_cycle+gpu_tot_sim_cycle, NULL /*should never writeback*/); accessq[i].cache_hit = (status == HIT); - if (gpgpu_perfect_mem) accessq[i].cache_hit = true; - if (accessq[i].cache_hit) L1_texture_miss++; + if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; + if (accessq[i].cache_hit) m_stats->L1_texture_miss++; accessq[i].cache_checked = true; } } -void shader_memory_global_process_inst(shader_core_ctx_t * shader, unsigned char* paths, std::vector<mem_access_t> &accessq) +void shader_core_ctx::memory_global_process_warp() { + std::vector<mem_access_t> &accessq = m_memory_queue.local_global; unsigned qbegin = accessq.size(); unsigned warp_parts = 1; - unsigned line_size = shader->L1cache->line_sz; - if (gpgpu_coalesce_arch == 13) { + unsigned line_size = m_L1D->line_sz; + if (m_config->gpgpu_coalesce_arch == 13) { warp_parts = 2; - if(gpgpu_no_dl1) { - int valindex = -1; - for (int i = 0; i < pipe_simd_width; i++) { - if (paths[i] == GLOBAL_MEM_PATH) { - valindex = i; - break; - } - } - assert(valindex != -1); + if(m_config->gpgpu_no_dl1) { + unsigned data_size = first_valid_thread( m_pipeline_reg[EX_MM] )->data_size; // line size is dependant on instruction; - //assume first valid thread instruction is the same as the rest. - switch (shader->pipeline_reg[EX_MM][valindex].data_size) { - case 1: - line_size = 32; - break; - case 2: - line_size = 64; - break; - case 4: - case 8: - case 16: - line_size = 128; - break; - default: - assert(0); + switch (data_size) { + case 1: line_size = 32; break; + case 2: line_size = 64; break; + case 4: case 8: case 16: line_size = 128; break; + default: assert(0); } } } - get_memory_access_list<&dcache_bank_func, &line_size_based_tag_func>(shader->pipeline_reg[EX_MM], paths, GLOBAL_MEM_PATH, - warp_parts, //warp parts - line_size, - false, //no broadcast limit. - accessq); + get_memory_access_list( &shader_core_ctx::dcache_bank_func, + &line_size_based_tag_func, + GLOBAL_MEM_PATH, + warp_parts, + line_size, + false, + accessq); + // Now that we have the accesses, if we don't have a cache we can adjust request sizes to + // include only the data referenced by the threads for (unsigned i = qbegin; i < accessq.size(); i++) { - if (gpgpu_coalesce_arch == 13 and gpgpu_no_dl1) { + if (m_config->gpgpu_coalesce_arch == 13 and m_config->gpgpu_no_dl1) { //if there is no l1 cache it makes sense to do coalescing here. //reduce memory request sizes. char* quarter_counts = accessq[i].quarter_count; @@ -2506,242 +1956,195 @@ void shader_memory_global_process_inst(shader_core_ctx_t * shader, unsigned char -mem_stage_stall_type send_mem_request(shader_core_ctx_t *shader, mem_access_t &access){ - inst_t* warp = shader->pipeline_reg[EX_MM]; +mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) +{ + //Atempt to send an request/write to memory based on information in access. + + inst_t* warp = m_pipeline_reg[EX_MM]; inst_t* req_head = warp + access.warp_indices[0]; + // If the cache told us it needed to write back a dirty line, do this now + // It is possible to do this writeback in the same cycle as the access request, this may not be realistic. if (access.need_wb) { - //fill out and send a writeback - unsigned req_size = shader->L1cache->line_sz + WRITE_PACKET_SIZE; - if (!(shader->fq_has_buffer(access.wb_addr, req_size, true, shader->sid))) { - gpu_stall_sh2icnt++; + unsigned req_size = m_L1D->line_sz + WRITE_PACKET_SIZE; + if ( ! m_gpu->fq_has_buffer(access.wb_addr, req_size, true, m_sid) ) { + m_stats->gpu_stall_sh2icnt++; return WB_ICNT_RC_FAIL; } - - shader->fq_push( access.wb_addr, - req_size, - true, NO_PARTIAL_WRITE, shader->sid, -1, NULL, - 0, - is_local(access.space)?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request + fq_push( access.wb_addr, req_size, true, NO_PARTIAL_WRITE, -1, NULL, 0, + is_local(access.space)?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request -1); - L1_writeback++; + m_stats->L1_writeback++; access.need_wb = false; } - bool requires_mshr = (shader->model != MIMD) and (not access.iswrite); - - //this decoding here might belong elsewhere unsigned code; - mem_access_type access_type; + mem_access_type access_type; switch(access.space.get_type()) { case const_space: - case param_space_kernel: - code = CONSTC; - access_type = CONST_ACC_R; - break; - case tex_space: - code = TEXTC; - access_type = TEXTURE_ACC_R; - break; - case global_space: - code = DCACHE; - access_type = (access.iswrite)? GLOBAL_ACC_W: GLOBAL_ACC_R; - break; + case param_space_kernel: code = CONSTC; access_type = CONST_ACC_R; break; + case tex_space: code = TEXTC; access_type = TEXTURE_ACC_R; break; + case global_space: code = DCACHE; access_type = (access.iswrite)? GLOBAL_ACC_W: GLOBAL_ACC_R; break; case local_space: - case param_space_local: - code = DCACHE; - access_type = (access.iswrite)? LOCAL_ACC_W: LOCAL_ACC_R; - break; - default: - assert(0); // NOT A MEM SPACE; - break; + case param_space_local: code = DCACHE; access_type = (access.iswrite)? LOCAL_ACC_W: LOCAL_ACC_R; break; + default: assert(0); break; } - //reserve mshr + bool requires_mshr = (m_config->model != MIMD) and (not access.iswrite); if (requires_mshr and not access.reserved_mshr) { - - // can allocate mshr? - if (not shader->mshr_unit->has_mshr(1)) { - //no mshr available; + if (not m_mshr_unit->has_mshr(1)) return MSHR_RC_FAIL; - } - - access.reserved_mshr = shader->mshr_unit->add_mshr(access, warp); + access.reserved_mshr = m_mshr_unit->add_mshr(access, warp); access.recheck_cache = false; //we have an mshr now, so have checked cache in same cycle as checking mshrs, so have merged if necessary. } - //require inct if access is this far without reserved mshr, or has and mshr but not merged with another request - bool requires_icnt = (not access.reserved_mshr) or (not access.reserved_mshr->merged_on_other_reqest); - + bool requires_icnt = (not access.reserved_mshr) or (not access.reserved_mshr->ismerged() ); if (requires_icnt) { - //calculate request size for icnt check (and later send); unsigned request_size = access.req_size; if (access.iswrite) { - if (requires_mshr) { - //needs information for a load back into cache. - request_size += READ_PACKET_SIZE + WRITE_MASK_SIZE; - } else { - //plain write - request_size += WRITE_PACKET_SIZE + WRITE_MASK_SIZE; - } + if (requires_mshr) + request_size += READ_PACKET_SIZE + WRITE_MASK_SIZE; // needs information for a load back into cache. + else + request_size += WRITE_PACKET_SIZE + WRITE_MASK_SIZE; //plain write } - - - // can allocate icnt? - //unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid); - if (!(shader->fq_has_buffer(access.addr, request_size, access.iswrite, shader->sid))) { - gpu_stall_sh2icnt++; - //std::cout<< "failed to push " << request_size << " bytes" << std::endl; + if ( !m_gpu->fq_has_buffer(access.addr, request_size, access.iswrite, m_sid) ) { + // can't allocate icnt + m_stats->gpu_stall_sh2icnt++; return ICNT_RC_FAIL; } - //send over interconnect - - unsigned cache_hits_waiting = 0; //fixme do we really want to be passing this in? - + unsigned cache_hits_waiting = 0; partial_write_mask_t write_mask = NO_PARTIAL_WRITE; + unsigned warp_id = req_head->hw_thread_id/m_config->warp_size; if (access.iswrite) { + if (!strcmp("GT200",m_config->pipeline_model) ) + m_warp[warp_id].inc_store_req(); for (unsigned i=0;i < access.warp_indices.size();i++) { unsigned w = access.warp_indices[i]; int data_offset = warp[w].memreqaddr & ((unsigned long long int)access.req_size - 1); for (unsigned b = data_offset; b < data_offset + warp[w].data_size; b++) write_mask.set(b); } - if (write_mask.count() != access.req_size) { - gpgpu_n_partial_writes++; - } + if (write_mask.count() != access.req_size) + m_stats->gpgpu_n_partial_writes++; } - - //typedef unsigned char (*fq_push_t)(unsigned long long int addr, int bsize, unsigned char readwrite, - // unsigned long long int partial_write_mask, - // int sid, int wid, mshr_entry* mshr, int cache_hits_waiting, - // enum mem_access_type mem_acc, address_type pc); - shader->fq_push( access.addr, - request_size, - access.iswrite, write_mask, shader->sid, req_head->hw_thread_id/warp_size, access.reserved_mshr, - cache_hits_waiting, access_type, req_head->pc); - + fq_push( access.addr, request_size, + access.iswrite, write_mask, warp_id , access.reserved_mshr, + cache_hits_waiting, access_type, req_head->pc); } - - //book keeping for mshr since this request is done (sent/accounted for) at this point; + // book keeping for mshr : this request is done (sent/accounted for) if (requires_mshr) { - for (unsigned i = 0; i < access.warp_indices.size(); i++) { unsigned o = access.warp_indices[i]; - shader->pending_mem_access++; - inflight_memory_insn_add(shader, &warp[o]); - -#if 0 //old stats - if (i > 0) { //maintain old stats (yes/no?) - shader->thread[warp[o].hw_thread_id].n_l1_mrghit_ac++; - shd_cache_mergehit(shader->L1texcache, warp[o].memreqaddr); //fixme; - } -#endif + m_pending_mem_access++; + if (enable_ptx_file_line_stats) + ptx_file_line_stats_add_inflight_memory_insn(m_sid, warp[o].pc); } // Scoreboard addition: do not make cache miss instructions wait for memory, // let the scoreboard handle stalling of instructions. // Mark thread as a cache miss - if (not access.iswrite) { // set the pipeline instructions in this request to noops, they all wait for memory; for (unsigned i = 0; i < access.warp_indices.size(); i++) { unsigned o = access.warp_indices[i]; - //shader->pipeline_reg[EX_MM][o] = nop_inst; - shader->pipeline_reg[EX_MM][o].cache_miss = true; + m_pipeline_reg[EX_MM][o].cache_miss = true; } } - } - return NO_RC_FAIL; } -bool shader_memory_shared_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq, - mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){ +bool shader_core_ctx::memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) +{ + // Process a single cycle of activity from the shared memory queue. + + std::vector<mem_access_t> &accessq = m_memory_queue.shared; //consume port number orders from the top of the queue; - for (unsigned i = 0; i < (unsigned) gpgpu_shmem_port_per_bank; i++) { - if (accessq.empty()) break; + for (int i = 0; i < m_config->gpgpu_shmem_port_per_bank; i++) { + if (accessq.empty()) + break; unsigned current_order = accessq.back().order; //consume all requests of the same order (concurrent bank requests) - while ((not accessq.empty()) and accessq.back().order == current_order) accessq.pop_back(); + while ((not accessq.empty()) and accessq.back().order == current_order) + accessq.pop_back(); } if (not accessq.empty()) { rc_fail = BK_CONF; fail_type = S_MEM; - gpgpu_n_shmem_bkconflict++; + m_stats->gpgpu_n_shmem_bkconflict++; } return accessq.empty(); //done if empty. } -//generic memory access queue processing, accessq must be sorted by order -//--that is, requests of similar order are expected to be contiguous in the queueu. -//if you want to use this for shared memory, make sure they are marked as cashe hits (not default) -// cycle_exec may be called multiple times if memory fails. typically used for cache checks -template < mem_stage_stall_type (*cycle_exec)(shader_core_ctx_t*, mem_access_t&) > -inline mem_stage_stall_type shader_memory_generic_process_queue( shader_core_ctx_t *shader, - unsigned ports_per_bank, unsigned memory_send_max, - std::vector<mem_access_t> &accessq ){ - mem_stage_stall_type rc_fail = NO_RC_FAIL; - // number of requests to sent to memory this cycle - unsigned mem_req_count = 0; - //consume port number orders from the top of the queue; +mem_stage_stall_type shader_core_ctx::process_memory_access_queue( shader_core_ctx::cache_check_t cache_check, + unsigned ports_per_bank, + unsigned memory_send_max, + std::vector<mem_access_t> &accessq ) +{ + // Generic algorithm for processing a single cycle of accesses for the memory space types that go to L2 or DRAM. + + // precondition: accessq sorted by mem_access_t::order + mem_stage_stall_type hazard_cond = NO_RC_FAIL; + unsigned mem_req_count = 0; // number of requests to sent to memory this cycle for (unsigned i = 0; i < ports_per_bank; i++) { - if (accessq.empty()) break; + if (accessq.empty()) + break; unsigned current_order = accessq.back().order; - //consume all requests of the same order (concurrent bank requests) - //stop when things that go to memory exceed a per cycle limit. - while ((not accessq.empty()) and accessq.back().order == current_order and rc_fail == NO_RC_FAIL) { - rc_fail = (*cycle_exec)(shader, accessq.back()); - if (rc_fail != NO_RC_FAIL) break; //can't complete this request this cycle. + // consume all requests of the same "order" but stop if we hit a structural hazard + while ((not accessq.empty()) and accessq.back().order == current_order and hazard_cond == NO_RC_FAIL) { + hazard_cond = (this->*cache_check)(accessq.back()); + if (hazard_cond != NO_RC_FAIL) + break; // can't complete this request this cycle. if (not accessq.back().cache_hit){ if (mem_req_count < memory_send_max) { mem_req_count++; - rc_fail = send_mem_request(shader, accessq.back()); //try to get mshr, icnt, send; + hazard_cond = send_mem_request(accessq.back()); // attemp to get mshr, icnt, send; } - else { - rc_fail = COAL_STALL; //not really a coal stall, its a too many memory request stall; - } - if (rc_fail != NO_RC_FAIL) break; //can't complete this request this cycle. + else hazard_cond = COAL_STALL; // not really a coal stall, its a too many memory request stall; + if ( hazard_cond != NO_RC_FAIL) break; //can't complete this request this cycle. } accessq.pop_back(); } } - if (not accessq.empty() and rc_fail == NO_RC_FAIL) { + if (not accessq.empty() and hazard_cond == NO_RC_FAIL) { //no resource failed so must be a bank comflict. - rc_fail = BK_CONF; + hazard_cond = BK_CONF; } - return rc_fail; + return hazard_cond; } -mem_stage_stall_type ccache_check(shader_core_ctx_t *shader, mem_access_t& access){ /*done in process queue*/ return NO_RC_FAIL;} +bool shader_core_ctx::memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) +{ + // Process a single cycle of activity from the the constant memory queue. -bool shader_memory_constant_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq, - mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){ + std::vector<mem_access_t> &accessq = m_memory_queue.constant; - mem_stage_stall_type fail = shader_memory_generic_process_queue<ccache_check>( shader, gpgpu_const_port_per_bank, - 1, //memory send max per cycle - accessq ); + mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::ccache_check, + m_config->gpgpu_const_port_per_bank, + 1, //memory send max per cycle + accessq ); if (fail != NO_RC_FAIL){ rc_fail = fail; //keep other fails if this didn't fail. fail_type = C_MEM; if (rc_fail == BK_CONF or rc_fail == COAL_STALL) { - gpgpu_n_cmem_portconflict++; //coal stalls aren't really a bank conflict, but this maintains previous behavior. + m_stats->gpgpu_n_cmem_portconflict++; //coal stalls aren't really a bank conflict, but this maintains previous behavior. } } return accessq.empty(); //done if empty. } -mem_stage_stall_type tcache_check(shader_core_ctx_t *shader, mem_access_t& access){ /*done in process queue*/ return NO_RC_FAIL;} - -bool shader_memory_texture_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq, - mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){ +bool shader_core_ctx::memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) +{ + // Process a single cycle of activity from the the texture memory queue. - mem_stage_stall_type fail = shader_memory_generic_process_queue<tcache_check>(shader, 1, //how is tex memory banked? - 1, //memory send max per cycle - accessq ); + std::vector<mem_access_t> &accessq = m_memory_queue.texture; + mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::tcache_check, + 1, //how is tex memory banked? + 1, //memory send max per cycle + accessq ); if (fail != NO_RC_FAIL){ rc_fail = fail; //keep other fails if this didn't fail. fail_type = T_MEM; @@ -2750,15 +2153,20 @@ bool shader_memory_texture_cycle( shader_core_ctx_t *shader, std::vector<mem_acc } -mem_stage_stall_type dcache_check(shader_core_ctx_t *shader, mem_access_t& access){ - if (access.cache_checked and not access.recheck_cache) return NO_RC_FAIL; - if (!gpgpu_no_dl1 && !gpgpu_perfect_mem) { +mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) +{ + // Global memory (data cache) checks the cache for each access at the time it is processed. + // This is more accurate to hardware, and necessary for proper action of the writeback cache. + + if (access.cache_checked and not access.recheck_cache) + return NO_RC_FAIL; + if (!m_config->gpgpu_no_dl1 && !m_config->gpgpu_perfect_mem) { //check cache - cache_request_status status = shd_cache_access_wb(shader->L1cache, + cache_request_status status = shd_cache_access_new(m_L1D, access.addr, WORD_SIZE, //this field is ignored. access.iswrite, - shader->gpu_cycle, + gpu_sim_cycle+gpu_tot_sim_cycle, &access.wb_addr); if (status == RESERVATION_FAIL) { access.cache_checked = false; @@ -2771,10 +2179,10 @@ mem_stage_stall_type dcache_check(shader_core_ctx_t *shader, mem_access_t& acces //write has hit a reserved cache line //it has writen its data into the cache line, so no need to go to memory access.cache_hit = true; - L1_write_hit_on_miss++; + m_stats->L1_write_hit_on_miss++; // here we would search the MSHRs for the originating read, // and mask off the writen bytes, so they are not overwritten in the cache when it comes back - // --- don't actually do this since we are pretending. + // --- don't actually do this since we don't functionally execute based upon values in cache // MSHR will still forward the unmasked value to its dependant reads. // if doing stall on use, must stall this thread after this write (otherwise, inproper values may be forwarded to future reads). } @@ -2788,404 +2196,217 @@ mem_stage_stall_type dcache_check(shader_core_ctx_t *shader, mem_access_t& acces access.cache_hit = false; } - if (gpgpu_perfect_mem) access.cache_hit = true; + if (m_config->gpgpu_perfect_mem) access.cache_hit = true; - //atomics always go to memory if (access.isatomic) { - if (!gpgpu_perfect_mem) { - access.cache_hit = false; - } else { - //unless perfect mem, in which case, the callback can only be done here - dram_callback_t &atom_exec = shader->pipeline_reg[EX_MM][access.warp_indices[0]].callback; + if (m_config->gpgpu_perfect_mem) { + // complete functional execution of atomic here + dram_callback_t &atom_exec = m_pipeline_reg[EX_MM][access.warp_indices[0]].callback; atom_exec.function(atom_exec.instruction, atom_exec.thread); + } else { + // atomics always go to memory + access.cache_hit = false; } } if (!access.cache_hit) { - if (access.iswrite) L1_write_miss++; - else L1_read_miss++; + if (access.iswrite) m_stats->L1_write_miss++; + else m_stats->L1_read_miss++; } return NO_RC_FAIL; } -bool shader_memory_global_cycle( shader_core_ctx_t *shader, std::vector<mem_access_t> &accessq, - mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type){ - mem_stage_stall_type fail = shader_memory_generic_process_queue<&dcache_check>(shader, gpgpu_cache_port_per_bank, - 1, //memory send max per cycle - accessq ); - if (fail != NO_RC_FAIL) { - rc_fail = fail; //keep other fails if this didn't fail. - //need to determine load/store, local/global: - bool iswrite = accessq.back().iswrite; - if (is_local(accessq.back().space)) { - fail_type = (iswrite)?L_MEM_ST:L_MEM_LD; - } else { - fail_type = (iswrite)?G_MEM_ST:G_MEM_LD; - } +bool shader_core_ctx::memory_cycle( mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type) +{ + // Process a single cycle of activity from the the global/local memory queue. - if (rc_fail == BK_CONF or rc_fail == COAL_STALL) { - gpgpu_n_cache_bkconflict++; - } - } - return accessq.empty(); //done if empty. -} + std::vector<mem_access_t> &accessq = m_memory_queue.local_global; + mem_stage_stall_type stall_cond = process_memory_access_queue(&shader_core_ctx::dcache_check, m_config->gpgpu_cache_port_per_bank, 1, accessq); -inline void mem_instruction_stats(inst_t* warp){ - //there must be a better way to count these - for (unsigned i=0; i< (unsigned) pipe_simd_width; i++) { - if (warp[i].hw_thread_id == -1) continue; //bubble - //this breaks some encapsulation: the is_[space] functions, if you change those, change this. - bool store = is_store(warp[i].op); - switch (warp[i].space.get_type()) { - case undefined_space: - case reg_space: - break; - case shared_space: - gpgpu_n_shmem_insn++; - break; - case const_space: - gpgpu_n_const_insn++; - break; - case param_space_kernel: - case param_space_local: - gpgpu_n_param_insn++; - break; - case tex_space: - gpgpu_n_tex_insn++; - break; - case global_space: - case local_space: - if (store){ - gpgpu_n_store_insn++; - } else { - gpgpu_n_load_insn++; - } - break; - default: - abort(); - } + if (stall_cond != NO_RC_FAIL) { + stall_reason = stall_cond; + bool iswrite = accessq.back().iswrite; + if (is_local(accessq.back().space)) + access_type = (iswrite)?L_MEM_ST:L_MEM_LD; + else + access_type = (iswrite)?G_MEM_ST:G_MEM_LD; + if (stall_cond == BK_CONF or stall_cond == COAL_STALL) + m_stats->gpgpu_n_cache_bkconflict++; } + return accessq.empty(); //done if empty. } -struct shader_queues_t{ - std::vector<mem_access_t> shared; - std::vector<mem_access_t> constant; - std::vector<mem_access_t> texture; - std::vector<mem_access_t> global; -}; - -void shader_memory_queue(shader_core_ctx_t *shader, shader_queues_t *accessqs) +void shader_core_ctx::memory_queue() { - //classify memory according to type; - static unsigned char *path = NULL; - if (!path) path = (unsigned char*)malloc(pipe_simd_width * sizeof(unsigned char)); - memset(path, 0, pipe_simd_width * sizeof(unsigned char)); - //static std::vector<char> path; - //path.clear(); path.resize(p, NO_MEM_PATH); - - static unsigned type_counts[NUM_MEM_PATHS]; - memset(type_counts, 0, sizeof(type_counts)); - //static std::vector<unsigned> type_counts; - //type_counts.clear(); type_counts.resize(NUM_MEM_PATHS); - - for (unsigned i=0; i< (unsigned) pipe_simd_width; i++) { - if (shader->pipeline_reg[EX_MM][i].hw_thread_id == -1) continue; //bubble - //this breaks some encapsulation: the is_[space] functions; if you change those, change this. - switch (shader->pipeline_reg[EX_MM][i].space.get_type()) { - case shared_space: - path[i] = SHARED_MEM_PATH; - type_counts[SHARED_MEM_PATH]++; - break; - case const_space: - case param_space_kernel: - path[i] = CONSTANT_MEM_PATH; - type_counts[CONSTANT_MEM_PATH]++; - break; - case tex_space: - path[i] = TEXTURE_MEM_PATH; - type_counts[TEXTURE_MEM_PATH]++; - break; - case global_space: - case local_space: - case param_space_local: - path[i] = GLOBAL_MEM_PATH; - type_counts[GLOBAL_MEM_PATH]++; - break; - case param_space_unclassified: - abort(); // todo: define access details - break; - default: - break; - } - } - - //instruction counting: - mem_instruction_stats(shader->pipeline_reg[EX_MM]); - - - if (type_counts[SHARED_MEM_PATH]) shader_memory_shared_process_inst(shader, path, accessqs->shared); - if (type_counts[CONSTANT_MEM_PATH]) shader_memory_const_process_inst(shader, path, accessqs->constant); - if (type_counts[TEXTURE_MEM_PATH]) shader_memory_texture_process_inst(shader, path, accessqs->texture); - if (type_counts[GLOBAL_MEM_PATH]) shader_memory_global_process_inst(shader, path, accessqs->global); + // Called once per warp when warp enters memory stage. + // Generates a list of memory accesses, but does not perform the memory access. + if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) ) + return; + m_gpu->mem_instruction_stats(m_pipeline_reg[EX_MM]); + inst_t *inst = first_valid_thread(m_pipeline_reg[EX_MM]); + switch (inst->space.get_type()) { + case shared_space: memory_shared_process_warp(); break; + case tex_space: memory_texture_process_warp(); break; + case const_space: case param_space_kernel: memory_const_process_warp(); break; + case global_space: case local_space: case param_space_local: memory_global_process_warp(); break; + case param_space_unclassified: abort(); break; + default: break; // non-memory operations + } } - -void shader_memory( shader_core_ctx_t *shader, unsigned int shader_number ) +void shader_core_ctx::memory() { - enum mem_stage_stall_type rc_fail = NO_RC_FAIL; // resource allocation - - //these should be local to the shader structure but can't because it is included in non c++ files. - //so provide static storage for it here - static std::vector<shader_queues_t> shader_memory_queues; - if (shader_memory_queues.size() == 0) { - shader_memory_queues.resize(gpu_n_shader); - for (unsigned i = 0; i < gpu_n_shader; i++) { - shader_memory_queues[i].shared.reserve(pipe_simd_width); - shader_memory_queues[i].constant.reserve(pipe_simd_width); - shader_memory_queues[i].texture.reserve(pipe_simd_width); - shader_memory_queues[i].global.reserve(pipe_simd_width); - } - } - shader_queues_t *accessqs = &(shader_memory_queues[shader->sid]); - - if (shader->shader_memory_new_instruction_processed == 0) { - shader->shader_memory_new_instruction_processed = 1; //only do this once per pipeline occupant - shader_memory_queue(shader, accessqs); + if (!m_shader_memory_new_instruction_processed) { + m_shader_memory_new_instruction_processed = true; // do once per warp instruction + memory_queue(); } - bool done = true; + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; mem_stage_access_type type; + done &= memory_shared_cycle(rc_fail, type); + done &= memory_constant_cycle(rc_fail, type); + done &= memory_texture_cycle(rc_fail, type); + done &= memory_cycle(rc_fail, type); - done &= shader_memory_shared_cycle(shader, accessqs->shared, rc_fail, type); - done &= shader_memory_constant_cycle(shader, accessqs->constant, rc_fail, type); - done &= shader_memory_texture_cycle(shader, accessqs->texture, rc_fail, type); - done &= shader_memory_global_cycle(shader, accessqs->global, rc_fail, type); - - //wb stalled? - int wb_stalled = 0; // check if next stage is stalled - for (unsigned i=0; i< (unsigned) pipe_simd_width; i++) { - if (shader->pipeline_reg[MM_WB][i].hw_thread_id != -1 ) { - wb_stalled = 1; - break; - } - } - - if (!done) { + if (!done) { // log stall types and return assert(rc_fail != NO_RC_FAIL); - //log stall types - gpu_stall_shd_mem++; - gpu_stall_shd_mem_breakdown[type][rc_fail]++; - } - - if (!done or wb_stalled) return; - - // this memory stage is done and not stalled by wb - // pipeline forward - - check_stage_pcs(shader,EX_MM); - // and pass instruction from EX_MM to MM_WB - for (unsigned i=0; i< (unsigned) pipe_simd_width; i++) { - if (shader->pipeline_reg[EX_MM][i].hw_thread_id == -1 ) - continue; // bubble - shader->pipeline_reg[MM_WB][i] = shader->pipeline_reg[EX_MM][i]; - shader->pipeline_reg[MM_WB][i].mm_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - shader->pipeline_reg[EX_MM][i] = nop_inst; - } - - // reflect the change to EX|MM pipeline register to the pre_mem stage - if (gpgpu_pre_mem_stages) { - check_stage_pcs(shader,EX_MM); - for (unsigned i=0;i< (unsigned)pipe_simd_width ;i++ ) - shader->pre_mem_pipeline[gpgpu_pre_mem_stages][i] = shader->pipeline_reg[EX_MM][i]; + m_stats->gpu_stall_shd_mem++; + m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++; + return; } + if( not pipeline_regster_empty( m_pipeline_reg[MM_WB] ) ) + return; // writeback stalled + check_stage_pcs(EX_MM); + move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]); } -int writeback_l1_miss =0 ; - - -void register_cta_thread_exit(shader_core_ctx_t *shader, int tid ) +void shader_core_ctx::register_cta_thread_exit(int tid ) { - if (gpgpu_cuda_sim && gpgpu_spread_blocks_across_cores) { - unsigned padded_cta_size = ptx_sim_cta_size(); - if (padded_cta_size%warp_size) { - padded_cta_size = ((padded_cta_size/warp_size)+1)*(warp_size); - } - int cta_num = tid/padded_cta_size; - assert( shader->cta_status[cta_num] > 0 ); - shader->cta_status[cta_num]--; - if (!shader->cta_status[cta_num]) { - shader->n_active_cta--; - shader->deallocate_barrier(cta_num); - shader_CTA_count_unlog(shader->sid, 1); - printf("GPGPU-Sim uArch: Shader %d finished CTA #%d (%lld,%lld)\n", shader->sid, cta_num, gpu_sim_cycle, gpu_tot_sim_cycle ); - } + shader_core_ctx *shader = this; + unsigned padded_cta_size = m_gpu->the_kernel().threads_per_cta(); + if (padded_cta_size%m_config->warp_size) + padded_cta_size = ((padded_cta_size/m_config->warp_size)+1)*(m_config->warp_size); + int cta_num = tid/padded_cta_size; + assert( shader->m_cta_status[cta_num] > 0 ); + shader->m_cta_status[cta_num]--; + if (!shader->m_cta_status[cta_num]) { + shader->m_n_active_cta--; + shader->deallocate_barrier(cta_num); + shader_CTA_count_unlog(shader->m_sid, 1); + printf("GPGPU-Sim uArch: Shader %d finished CTA #%d (%lld,%lld)\n", shader->m_sid, cta_num, gpu_sim_cycle, gpu_tot_sim_cycle ); } } -void obtain_insn_latency_info(insn_latency_info *latinfo, inst_t *insn) +void obtain_insn_latency_info(insn_latency_info *latinfo, const inst_t *insn) { latinfo->pc = insn->pc; - latinfo->latency = gpu_tot_sim_cycle + gpu_sim_cycle - insn->ts_cycle; - latinfo->ptx_thd_info = insn->ptx_thd_info; + latinfo->latency = gpu_tot_sim_cycle + gpu_sim_cycle - insn->issue_cycle; } int debug_tid = 0; -unsigned gpu_n_max_mshr_writeback=1; -void shader_writeback( shader_core_ctx_t *shader, unsigned int shader_number, int grid_num ) +void shader_core_ctx::writeback() { std::vector<inst_t> done_insts; - - static int *mshr_tid = NULL; - static int *pl_tid = NULL; - std::vector<insn_latency_info> unlock_lat_infos; - static insn_latency_info *mshr_lat_info = NULL; - static insn_latency_info *pl_lat_info = NULL; - - mshr_entry *mshr_head = NULL; - - int tid; - op_type op; - int o1, o2, o3, o4; - bool stalled_by_MSHR = false; - bool writeback_by_MSHR = false; bool w2rf = false; + memset(m_pl_tid,-1, sizeof(int)*m_config->warp_size); + check_stage_pcs(MM_WB); - if ( mshr_tid == NULL ) { - mshr_tid = (int*) malloc(sizeof(int)*pipe_simd_width); - pl_tid = (int*) malloc(sizeof(int)*pipe_simd_width); - mshr_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * pipe_simd_width); - pl_lat_info = (insn_latency_info*) malloc(sizeof(insn_latency_info) * pipe_simd_width); - } - - memset(mshr_tid, -1, sizeof(int)*pipe_simd_width); - memset(pl_tid, -1, sizeof(int)*pipe_simd_width); - - - check_stage_pcs(shader,MM_WB); - - /* Generate Condition for instruction writeback to register file. */ - for (int i=0; i<pipe_simd_width; i++) { - w2rf |= (shader->pipeline_reg[MM_WB][i].hw_thread_id >= 0); - pl_tid[i] = shader->pipeline_reg[MM_WB][i].hw_thread_id; + // detect if a valid instruction is in MM_WB + for (unsigned i=0; i<m_config->warp_size; i++) { + w2rf |= (m_pipeline_reg[MM_WB][i].hw_thread_id >= 0); + m_pl_tid[i] = m_pipeline_reg[MM_WB][i].hw_thread_id; } //check mshrs for commit; unsigned mshr_threads_unlocked = 0; - for (unsigned i = 0; i < gpu_n_max_mshr_writeback; i++) { - mshr_head = shader->mshr_unit->return_head(); - if (mshr_head) { - //bail if we can't unlock anymore threads - if (mshr_threads_unlocked + mshr_head->insts.size() > (unsigned) pipe_simd_width) break; - assert(!gpgpu_strict_simd_wrbk);//implementation removed - assert (mshr_head->insts.size()); - for (unsigned j = 0; j < mshr_head->insts.size(); j++) { - inst_t &insn = mshr_head->insts[j]; + bool stalled_by_MSHR = false; + + mshr_entry *mshr_head = m_mshr_unit->return_head(); + if (mshr_head && (mshr_threads_unlocked + mshr_head->num_inst() <= m_config->warp_size) ) { + assert (mshr_head->num_inst()); + for (unsigned j = 0; j < mshr_head->num_inst(); j++) { + const inst_t &insn = mshr_head->get_inst(j); time_vector_update(insn.uid,MR_WRITEBACK,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ); - obtain_insn_latency_info(&mshr_lat_info[mshr_threads_unlocked], &(mshr_head->insts[j])); - inflight_memory_insn_sub(shader, &mshr_head->insts[j]); + obtain_insn_latency_info(&m_mshr_lat_info[mshr_threads_unlocked], &insn); + if (enable_ptx_file_line_stats) + ptx_file_line_stats_sub_inflight_memory_insn(m_sid, insn.pc); assert (insn.hw_thread_id >= 0); - shader->pending_mem_access--; - // for ensuring that we don't unlock more than the code allows, needs to be fixed. + m_pending_mem_access--; mshr_threads_unlocked++; - } - done_insts.insert(done_insts.end(), mshr_head->insts.begin(), mshr_head->insts.end()); + if (m_config->gpgpu_operand_collector) { + if ( j== 0 ) + m_operand_collector.writeback(insn); + } else + stalled_by_MSHR = true; + } + mshr_head->get_insts(done_insts); - shader->mshr_unit->pop_return_head(); - writeback_by_MSHR = true; - unlock_lat_infos.resize(mshr_threads_unlocked); - std::copy(mshr_lat_info, mshr_lat_info + mshr_threads_unlocked, unlock_lat_infos.begin()); - - if (w2rf) { - stalled_by_MSHR = true; - } - assert(mshr_threads_unlocked); - } - } - if (stalled_by_MSHR) { - gpu_stall_by_MSHRwb++; - } - - if (!writeback_by_MSHR) { //!writeback_by_MSHR - memory_space_t warp_space = undefined_space; - - for (int i=0; i<pipe_simd_width; i++) { - op = shader->pipeline_reg[MM_WB][i].op; - tid = shader->pipeline_reg[MM_WB][i].hw_thread_id; - o1 = shader->pipeline_reg[MM_WB][i].out[0]; - o2 = shader->pipeline_reg[MM_WB][i].out[1]; - o3 = shader->pipeline_reg[MM_WB][i].out[2]; - o4 = shader->pipeline_reg[MM_WB][i].out[3]; - - obtain_insn_latency_info(&pl_lat_info[i], &shader->pipeline_reg[MM_WB][i]); - - // Collect threads that are done - // Do not include cache misses for a writeback - if(!shader->pipeline_reg[MM_WB][i].cache_miss) { - if(shader->pipeline_reg[MM_WB][i].hw_thread_id > -1) { - done_insts.push_back(shader->pipeline_reg[MM_WB][i]); - unlock_lat_infos.push_back(pl_lat_info[i]); - } - } + m_mshr_unit->pop_return_head(); + unlock_lat_infos.resize(mshr_threads_unlocked); + std::copy(m_mshr_lat_info, m_mshr_lat_info + mshr_threads_unlocked, unlock_lat_infos.begin()); + assert(mshr_threads_unlocked); + } - // All threads in the warp should have the same pc and space - if(pl_tid[i] > -1 ) { - warp_space = shader->pipeline_reg[MM_WB][i].space; - } + if ( m_config->gpgpu_operand_collector ) + stalled_by_MSHR = !m_operand_collector.writeback( m_pipeline_reg[MM_WB] ); - if(tid > -1) { -/* - if(!shader->pipeline_reg[MM_WB][i].cache_miss) - printf("CACHE HIT sid=%d tid=%d pc=%d \n", shader->sid, tid, shader->pipeline_reg[MM_WB][i].pc); - else - printf("CACHE MISS sid=%d tid=%d pc=%d \n", shader->sid, tid, shader->pipeline_reg[MM_WB][i].pc); -*/ - } - } + if (!stalled_by_MSHR) { + inst_t inst; + for (unsigned i=0; i<m_config->warp_size; i++) { + op_type op; + if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1) + op = m_pipeline_reg[MM_WB][i].op; + obtain_insn_latency_info(&m_pl_lat_info[i], &m_pipeline_reg[MM_WB][i]); + if (!m_pipeline_reg[MM_WB][i].cache_miss) { // Do not include cache misses for a writeback + if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1) { + done_insts.push_back(m_pipeline_reg[MM_WB][i]); + unlock_lat_infos.push_back(m_pl_lat_info[i]); + } + } + if (m_pl_tid[i] > -1 ) + inst = m_pipeline_reg[MM_WB][i]; + } - // Unlock the warp for re-fetching (put it in the fixed delay queue) - // Only need to unlock if warp is not empty - if(w2rf) - shader_queue_warp_unlocking(shader, pl_tid, warp_space, grid_num); - } + // Unlock the warp for re-fetching (put it in the fixed delay queue) + if (w2rf) // Only need to unlock if this is a valid instruction + queue_warp_unlocking(m_pl_tid, inst); + } else + m_stats->gpu_stall_by_MSHRwb++; - // Mark threads as done in warp tracker for (unsigned i=0; i<done_insts.size(); i++) { inst_t done_inst = done_insts[i]; - - shader_call_thread_done(shader, grid_num, done_inst); - - // Statistics - // At any rate, a real instruction is committed - // - don't count cache miss - gpu_sim_insn++; + call_thread_done(done_inst); + + gpu_sim_insn++; // a (scalar) instruction is done if ( !is_const(done_inst.space) ) - gpu_sim_insn_no_ld_const++; - gpu_sim_insn_last_update = gpu_sim_cycle; - shader->num_sim_insn++; - shader->thread[done_inst.hw_thread_id].n_insn++; - shader->thread[done_inst.hw_thread_id].n_insn_ac++; + m_stats->gpu_sim_insn_no_ld_const++; + m_gpu->gpu_sim_insn_last_update = gpu_sim_cycle; + m_num_sim_insn++; + m_thread[done_inst.hw_thread_id].n_insn++; + m_thread[done_inst.hw_thread_id].n_insn_ac++; if (enable_ptx_file_line_stats) { unsigned pc = unlock_lat_infos[i].pc; unsigned long latency = unlock_lat_infos[i].latency; - ptx_file_line_stats_add_latency(unlock_lat_infos[i].ptx_thd_info, pc, latency); + ptx_file_line_stats_add_latency(pc, latency); } - } - /* The pipeline can be stalled by MSHR */ - if (!stalled_by_MSHR) { - for (int i=0; i<pipe_simd_width; i++) { - shader->pipeline_reg[WB_RT][i] = shader->pipeline_reg[MM_WB][i]; - shader->pipeline_reg[MM_WB][i] = nop_inst; + if (!stalled_by_MSHR) { + if (!strcmp("GT200",m_config->pipeline_model) ) { + inst_t *fvt=first_valid_thread(m_pipeline_reg[MM_WB]); + if( fvt ) { + unsigned warp_id = fvt->hw_thread_id/m_config->warp_size; + m_warp[warp_id].dec_inst_in_pipeline(); } - } + } + move_warp(m_pipeline_reg[WB_RT], m_pipeline_reg[MM_WB]); + } - // Process the delay queue for current cycle - shader_process_delay_queue(shader); + process_delay_queue(); } /* @@ -3193,21 +2414,18 @@ void shader_writeback( shader_core_ctx_t *shader, unsigned int shader_number, in * * The amount of delay to add is determined by the instruction type. * - * @param *shader Pointer to shader core * @param *tid Array of tid in the warp to unlock - * @param pc Program counter for the current instruction in the warp * @param space Address space for the current instruction in the warp * */ -void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_space_t space, int grid_num) { - +void shader_core_ctx::queue_warp_unlocking(int *tids, const inst_t &inst ) +{ // Create a delay queue object and add it to the queue - shader_core_ctx_t::fixeddelay_queue_warp_t fixeddelay_queue_warp; - - fixeddelay_queue_warp.grid_num = grid_num; + fixeddelay_queue_warp_t fixeddelay_queue_warp; // Set ready_cycle based on instruction space - switch(space.get_type()) { + fixeddelay_queue_warp.inst = inst; + switch(inst.space.get_type()) { case shared_space: fixeddelay_queue_warp.ready_cycle = gpu_tot_sim_cycle + gpu_sim_cycle + 5; // Adds 5*4=20 cycles break; @@ -3217,10 +2435,9 @@ void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_sp } // Store threads in delay queue warp object - fixeddelay_queue_warp.tids.resize(warp_size); - std::copy(tids, tids+warp_size, fixeddelay_queue_warp.tids.begin()); - - shader->fixeddelay_queue.insert(fixeddelay_queue_warp); + fixeddelay_queue_warp.tids.resize(m_config->warp_size); + std::copy(tids, tids+m_config->warp_size, fixeddelay_queue_warp.tids.begin()); + m_fixeddelay_queue.insert(fixeddelay_queue_warp); } /* @@ -3229,22 +2446,23 @@ void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_sp * @param *shader Pointer to shader core * */ -void shader_process_delay_queue(shader_core_ctx_t *shader) { +void shader_core_ctx::process_delay_queue() { + shader_core_ctx *shader=this; // Unlock warps in fixeddelay_queue_warp - std::multiset<shader_core_ctx_t::fixeddelay_queue_warp_t, shader_core_ctx_t::fixeddelay_queue_warp_comp>::iterator it; - std::multiset<shader_core_ctx_t::fixeddelay_queue_warp_t, shader_core_ctx_t::fixeddelay_queue_warp_comp>::iterator it_last; - for ( it=shader->fixeddelay_queue.begin() ; - it != shader->fixeddelay_queue.end(); + std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it; + std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it_last; + for ( it=shader->m_fixeddelay_queue.begin() ; + it != shader->m_fixeddelay_queue.end(); ) { if(it->ready_cycle <= gpu_tot_sim_cycle + gpu_sim_cycle) { - if(!gpgpu_stall_on_use) { + if(!m_config->gpgpu_stall_on_use) { // This disables stall-on-use // If thread is still in warp_tracker, do not unlock yet bool skip_unlock = false; - for(unsigned i=0; i<warp_size; i++) { + for(unsigned i=0; i<m_config->warp_size; i++) { int tid = it->tids[i]; if(tid < 0) continue; - if(get_warp_tracker_pool().wpt_thread_in_wpt(shader,tid)) { + if(m_warp_tracker->wpt_thread_in_wpt(tid)) { skip_unlock = true; break; } @@ -3255,12 +2473,24 @@ void shader_process_delay_queue(shader_core_ctx_t *shader) { } } - // Unlock warp - shader_unlock_warp(shader,it->tids, it->grid_num); + if (!strcmp("GT200",m_config->pipeline_model) ) { + if( it->inst.space == shared_space ) { + for(unsigned i=0; i < m_config->warp_size; i++ ) { + if( it->tids[i]>= 0 ) { + unsigned warp_id = it->tids[i]/m_config->warp_size; + m_scoreboard->releaseRegisters(warp_id,&it->inst); + break; + } + } + } + } + + // Unlock warp + unlock_warp(it->tids); // Remove warp information from delay queue it_last = it++; - shader->fixeddelay_queue.erase(it_last); + shader->m_fixeddelay_queue.erase(it_last); } else { break; } @@ -3270,70 +2500,61 @@ void shader_process_delay_queue(shader_core_ctx_t *shader) { /* * Unlock a warp * - * @param *shd Pointer to shader core * @param tids Vector of tid in the warp to unlock * */ -void shader_unlock_warp(shader_core_ctx_t *shd, std::vector<int> tids, int grid_num) { - int thd_unlocked = 0; - int thd_exited = 0; - int tid; - int valid_tid = -1; - // Unlock - for (unsigned i=0; i<warp_size; i++) { - tid = tids[i]; - if (tid >= 0) { - valid_tid = tid; - // thread completed if it is going to fetching beyond code boundary - if ( gpgpu_cuda_sim && ptx_thread_done(shd->thread[tid].ptx_thd_info) ) { - shd->not_completed -= 1; - gpu_completed_thread += 1; - - int warp_id = wid_from_hw_tid(tid,warp_size); - if (!(shd->warp[warp_id].n_completed < (unsigned)warp_size)) { - printf("shader[%d]->warp[%d].n_completed = %d; warp_size = %d\n", - shd->sid,warp_id, shd->warp[warp_id].n_completed, warp_size); - } - assert( shd->warp[warp_id].n_completed < (unsigned)warp_size ); - shd->warp[warp_id].n_completed++; - if ( shd->model == NO_RECONVERGE ) { - update_max_branch_priority(shd,warp_id,grid_num); - } - - register_cta_thread_exit(shd, tid ); - thd_exited = 1; - - //printf("THREAD EXIT sid=%d tid=%d \n", shd->sid, tid); - - } else { - shd->thread[tid].avail4fetch++; - assert(shd->thread[tid].avail4fetch <= 1); - assert( shd->warp[tid/warp_size].n_avail4fetch < warp_size ); - shd->warp[tid/warp_size].n_avail4fetch++; - thd_unlocked = 1; - - //printf("THREAD UNLOCK sid=%d tid=%d \n", shd->sid, tid); - } - } - } - - // Update warp was unlocked, update the warp active mask - if(thd_unlocked || thd_exited) { - // Update the warp active mask - shader_pdom_update_warp_mask(shd, wid_from_hw_tid(valid_tid,warp_size)); - } +void shader_core_ctx::unlock_warp( std::vector<int> tids ) +{ + assert( tids.size() == m_config->warp_size ); // required by thd_commit_queue usage in fetch_simd_dwf() + int thd_unlocked = 0; + int thd_exited = 0; + int tid; + int valid_tid = -1; + if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { + // Unlock + for (unsigned i=0; i<m_config->warp_size; i++) { + tid = tids[i]; + if (tid >= 0) { + valid_tid = tid; + // thread completed if it is going to fetching beyond code boundary + if ( ptx_thread_done(tid) ) { + m_not_completed -= 1; + m_stats->gpu_completed_thread += 1; + int warp_id = wid_from_hw_tid(tid,m_config->warp_size); + if (!(m_warp[warp_id].get_n_completed() < m_config->warp_size)) + printf("GPGPU-Sim uArch: shader[%d]->warp[%d].n_completed = %d; warp_size = %d\n", + m_sid,warp_id, m_warp[warp_id].get_n_completed(), m_config->warp_size); + assert( m_warp[warp_id].get_n_completed() < m_config->warp_size ); + m_warp[warp_id].inc_n_completed(); + register_cta_thread_exit( tid ); + thd_exited = 1; + } else { + if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { + assert(!m_thread[tid].m_avail4fetch); + m_thread[tid].m_avail4fetch=true; + assert( m_warp[tid/m_config->warp_size].get_avail4fetch() < m_config->warp_size ); + m_warp[tid/m_config->warp_size].inc_avail4fetch(); + } + thd_unlocked = 1; + } + } + } + } + if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { + if(thd_unlocked || thd_exited) { + // Update the warp active mask + m_pdom_warp[wid_from_hw_tid(valid_tid,m_config->warp_size)]->pdom_update_warp_mask(); + } + } - if (shd->model == POST_DOMINATOR || shd->model == NO_RECONVERGE) { + if (m_config->model == POST_DOMINATOR) { // Do nothing } else { // For this case, submit to commit_queue - if (shd->using_commit_queue && thd_unlocked) { - int *tid_unlocked = alloc_commit_warp(); - std::copy(tids.begin(), tids.end(), tid_unlocked); - dq_push(shd->thd_commit_queue,(void*)tid_unlocked); - } + if (m_config->using_commit_queue && thd_unlocked) + m_thd_commit_queue->push( new std::vector<int>(tids), gpu_sim_cycle ); } } @@ -3342,93 +2563,73 @@ void shader_unlock_warp(shader_core_ctx_t *shd, std::vector<int> tids, int grid_ * Signals to the warp_tracker that a thread in a warp (for a given pc/instruction) is done * * @param *shd Pointer to shader core - * @param grid_num Grid number * @param done_inst Completed instruction * */ -void shader_call_thread_done( shader_core_ctx_t *shader, int grid_num, inst_t &done_inst ) { - - if (gpgpu_no_divg_load) { - - //printf("THREAD RETURNED sid=%d tid=%d pc=%d \n", shader->sid, done_inst.hw_thread_id, done_inst.pc); - +void shader_core_ctx::call_thread_done( inst_t &done_inst ) +{ + if (m_config->gpgpu_no_divg_load) { // Signal to unlock the thread. If all threads are done, deregister warp - if( get_warp_tracker_pool().wpt_signal_avail(done_inst.hw_thread_id, shader, done_inst.pc) == 1 ) { + if( m_warp_tracker->wpt_signal_avail(done_inst.hw_thread_id, done_inst.pc) == 1 ) { // Entire warp has returned - //printf("WARP RETURNED sid=%d tid=%d pc=%d \n", shader->sid, done_inst.hw_thread_id, done_inst.pc); - // Deregister warp - get_warp_tracker_pool().wpt_deregister_warp(done_inst.hw_thread_id, shader, done_inst.pc); - - // Signal scoreboard to release register - shader->scrb->releaseRegisters( wid_from_hw_tid(done_inst.hw_thread_id, warp_size), &done_inst ); + m_warp_tracker->wpt_deregister_warp(done_inst.hw_thread_id, done_inst.pc); + if (! (!strcmp("GT200",m_config->pipeline_model) && (done_inst.space == shared_space)) ) + // Signal scoreboard to release register + m_scoreboard->releaseRegisters( wid_from_hw_tid(done_inst.hw_thread_id, m_config->warp_size), &done_inst ); } } - } -void shader_print_runtime_stat( FILE *fout ) { - unsigned i; - +void gpgpu_sim::shader_print_runtime_stat( FILE *fout ) +{ fprintf(fout, "SHD_INSN: "); - for (i=0;i<gpu_n_shader;i++) { - fprintf(fout, "%u ",sc[i]->num_sim_insn); - } + for (unsigned i=0;i<m_n_shader;i++) + fprintf(fout, "%u ",m_sc[i]->get_num_sim_insn()); fprintf(fout, "\n"); fprintf(fout, "SHD_THDS: "); - for (i=0;i<gpu_n_shader;i++) { - fprintf(fout, "%u ",sc[i]->not_completed); - } + for (unsigned i=0;i<m_n_shader;i++) + fprintf(fout, "%u ",m_sc[i]->get_not_completed()); fprintf(fout, "\n"); fprintf(fout, "SHD_DIVG: "); - for (i=0;i<gpu_n_shader;i++) { - fprintf(fout, "%u ",sc[i]->n_diverge); - } + for (unsigned i=0;i<m_n_shader;i++) + fprintf(fout, "%u ",m_sc[i]->get_n_diverge()); fprintf(fout, "\n"); fprintf(fout, "THD_INSN: "); - for (i=0; i<gpu_n_thread_per_shader; i++) { - fprintf(fout, "%d ", sc[0]->thread[i].n_insn); - } + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) + fprintf(fout, "%d ", m_sc[0]->get_thread_n_insn(i) ); fprintf(fout, "\n"); } -void shader_print_l1_miss_stat( FILE *fout ) { - unsigned i; - +void gpgpu_sim::shader_print_l1_miss_stat( FILE *fout ) +{ fprintf(fout, "THD_INSN_AC: "); - for (i=0; i<gpu_n_thread_per_shader; i++) { - fprintf(fout, "%d ", sc[0]->thread[i].n_insn_ac); - } + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) + fprintf(fout, "%d ", m_sc[0]->get_thread_n_insn_ac(i)); fprintf(fout, "\n"); - fprintf(fout, "T_L1_Mss: "); //l1 miss rate per thread - for (i=0; i<gpu_n_thread_per_shader; i++) { - fprintf(fout, "%d ", sc[0]->thread[i].n_l1_mis_ac); - } + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) + fprintf(fout, "%d ", m_sc[0]->get_thread_n_l1_mis_ac(i)); fprintf(fout, "\n"); - fprintf(fout, "T_L1_Mgs: "); //l1 merged miss rate per thread - for (i=0; i<gpu_n_thread_per_shader; i++) { - fprintf(fout, "%d ", sc[0]->thread[i].n_l1_mis_ac - sc[0]->thread[i].n_l1_mrghit_ac); - } + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) + fprintf(fout, "%d ", m_sc[0]->get_thread_n_l1_mis_ac(i) - m_sc[0]->get_thread_n_l1_mrghit_ac(i)); fprintf(fout, "\n"); - fprintf(fout, "T_L1_Acc: "); //l1 access per thread - for (i=0; i<gpu_n_thread_per_shader; i++) { - fprintf(fout, "%d ", sc[0]->thread[i].n_l1_access_ac); - } + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) + fprintf(fout, "%d ", m_sc[0]->get_thread_n_l1_access_ac(i)); fprintf(fout, "\n"); //per warp int temp =0; fprintf(fout, "W_L1_Mss: "); //l1 miss rate per warp - for (i=0; i<gpu_n_thread_per_shader; i++) { - temp += sc[0]->thread[i].n_l1_mis_ac; - if (i%warp_size == (unsigned)(warp_size-1)) { + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) { + temp += m_sc[0]->get_thread_n_l1_mis_ac(i); + if (i%m_shader_config->warp_size == (unsigned)(m_shader_config->warp_size-1)) { fprintf(fout, "%d ", temp); temp = 0; } @@ -3436,9 +2637,9 @@ void shader_print_l1_miss_stat( FILE *fout ) { fprintf(fout, "\n"); temp=0; fprintf(fout, "W_L1_Mgs: "); //l1 merged miss rate per warp - for (i=0; i<gpu_n_thread_per_shader; i++) { - temp += (sc[0]->thread[i].n_l1_mis_ac - sc[0]->thread[i].n_l1_mrghit_ac); - if (i%warp_size == (unsigned)(warp_size-1)) { + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) { + temp += (m_sc[0]->get_thread_n_l1_mis_ac(i) - m_sc[0]->get_thread_n_l1_mrghit_ac(i) ); + if (i%m_shader_config->warp_size == (unsigned)(m_shader_config->warp_size-1)) { fprintf(fout, "%d ", temp); temp = 0; } @@ -3446,49 +2647,51 @@ void shader_print_l1_miss_stat( FILE *fout ) { fprintf(fout, "\n"); temp =0; fprintf(fout, "W_L1_Acc: "); //l1 access per warp - for (i=0; i<gpu_n_thread_per_shader; i++) { - temp += sc[0]->thread[i].n_l1_access_ac; - if (i%warp_size == (unsigned)(warp_size-1)) { + for (unsigned i=0; i<m_shader_config->n_thread_per_shader; i++) { + temp += m_sc[0]->get_thread_n_l1_access_ac(i); + if (i%m_shader_config->warp_size == (unsigned)(m_shader_config->warp_size-1)) { fprintf(fout, "%d ", temp); temp = 0; } } fprintf(fout, "\n"); - } -void shader_print_warp( const shader_core_ctx_t *shader, inst_t *warp, FILE *fout, int stage_width, int print_mem, int mask ) +void shader_core_ctx::print_warp( inst_t *warp, FILE *fout, int print_mem, int mask ) const { - int i, j, warp_id = -1; - for (i=0; i<stage_width; i++) { + unsigned i, j, warp_id = (unsigned)-1; + for (i=0; i<m_config->warp_size; i++) { if (warp[i].hw_thread_id > -1) { - warp_id = warp[i].hw_thread_id / warp_size; + warp_id = warp[i].hw_thread_id / m_config->warp_size; break; } } - i = (i>=stage_width)? 0 : i; + i = (i>=m_config->warp_size)? 0 : i; - fprintf(fout,"0x%04x ", warp[i].pc ); + if( warp[i].pc != (address_type)-1 ) + fprintf(fout,"0x%04x ", warp[i].pc ); + else + fprintf(fout,"bubble " ); if( mask & 2 ) { fprintf(fout, "(" ); - for (j=0; j<stage_width; j++) + for (j=0; j<m_config->warp_size; j++) fprintf(fout, "%03d ", warp[j].hw_thread_id); fprintf(fout, "): "); } else { fprintf(fout, "w%02d[", warp_id); - for (j=0; j<stage_width; j++) + for (j=0; j<m_config->warp_size; j++) fprintf(fout, "%c", ((warp[j].hw_thread_id != -1)?'1':'0') ); fprintf(fout, "]: "); } - if( warp_id != -1 && shader->model == POST_DOMINATOR ) { - pdom_warp_ctx_t *warp=&(shader->pdom_warp[warp_id]); - if( warp->m_recvg_pc[warp->m_stack_top] == (unsigned)-1 ) { - fprintf(fout," rp:--- "); - } else { - fprintf(fout," rp:0x%03x ", warp->m_recvg_pc[warp->m_stack_top] ); - } + if( warp_id != (unsigned)-1 && m_config->model == POST_DOMINATOR ) { + unsigned rp = m_pdom_warp[warp_id]->get_rp(); + if( rp == (unsigned)-1 ) { + fprintf(fout," rp:--- "); + } else { + fprintf(fout," rp:0x%03x ", rp ); + } } ptx_print_insn( warp[i].pc, fout ); @@ -3501,62 +2704,64 @@ void shader_print_warp( const shader_core_ctx_t *shader, inst_t *warp, FILE *fou fprintf(fout, "\n"); } -void shader_print_stage(shader_core_ctx_t *shader, unsigned int stage, - FILE *fout, int stage_width, int print_mem, int mask ) +void shader_core_ctx::print_stage(unsigned int stage, FILE *fout, int print_mem, int mask ) { - inst_t *warp = shader->pipeline_reg[stage]; - shader_print_warp(shader,warp,fout,stage_width,print_mem,mask); + inst_t *warp = m_pipeline_reg[stage]; + print_warp(warp,fout,print_mem,mask); } -void shader_print_pre_mem_stages(shader_core_ctx_t *shader, FILE *fout, int print_mem, int mask ) +void shader_core_ctx::print_pre_mem_stages( FILE *fout, int print_mem, int mask ) { - int i, j; + unsigned i, j; int warp_id; - if (!gpgpu_pre_mem_stages) return; + if (!m_config->gpgpu_pre_mem_stages) return; - for (unsigned pms = 0; pms <= gpgpu_pre_mem_stages - 1; pms++) { - fprintf(fout, "PM[%01d] = ", pms); + for (unsigned pms = 0; pms <= m_config->gpgpu_pre_mem_stages; pms++) { + fprintf(fout, "PM[%01d] = ", pms); warp_id = -1; - for (i=0; i<pipe_simd_width; i++) { - if (shader->pre_mem_pipeline[pms][i].hw_thread_id > -1) { - warp_id = shader->pre_mem_pipeline[pms][i].hw_thread_id / warp_size; + for (i=0; i<m_config->warp_size; i++) { + if (pre_mem_pipeline[pms][i].hw_thread_id > -1) { + warp_id = pre_mem_pipeline[pms][i].hw_thread_id / m_config->warp_size; break; } } - i = (i>=pipe_simd_width)? 0 : i; + i = (i>=m_config->warp_size)? 0 : i; - fprintf(fout,"0x%04x ", shader->pre_mem_pipeline[pms][i].pc ); + if( pre_mem_pipeline[pms][i].pc != (address_type)-1 ) + fprintf(fout,"0x%04x ", pre_mem_pipeline[pms][i].pc ); + else + fprintf(fout,"bubble " ); if( mask & 2 ) { fprintf(fout, "(" ); - for (j=0; j<pipe_simd_width; j++) - fprintf(fout, "%03d ", shader->pre_mem_pipeline[pms][j].hw_thread_id); + for (j=0; j<m_config->warp_size; j++) + fprintf(fout, "%03d ", pre_mem_pipeline[pms][j].hw_thread_id); fprintf(fout, "): "); } else { fprintf(fout, "w%02d[", warp_id); - for (j=0; j<pipe_simd_width; j++) - fprintf(fout, "%c", ((shader->pre_mem_pipeline[pms][j].hw_thread_id != -1)?'1':'0') ); + for (j=0; j<m_config->warp_size; j++) + fprintf(fout, "%c", ((pre_mem_pipeline[pms][j].hw_thread_id != -1)?'1':'0') ); fprintf(fout, "]: "); } - if( warp_id != -1 && shader->model == POST_DOMINATOR ) { - pdom_warp_ctx_t *warp=&(shader->pdom_warp[warp_id]); - if( warp->m_recvg_pc[warp->m_stack_top] == (unsigned)-1 ) { - printf(" rp:--- "); - } else { - printf(" rp:0x%03x ", warp->m_recvg_pc[warp->m_stack_top] ); - } + if( warp_id != -1 && m_config->model == POST_DOMINATOR ) { + unsigned rp = m_pdom_warp[warp_id]->get_rp(); + if( rp == (unsigned)-1 ) { + fprintf(fout," rp:--- "); + } else { + fprintf(fout," rp:0x%03x ", rp ); + } } - ptx_print_insn( shader->pre_mem_pipeline[pms][i].pc, fout ); + ptx_print_insn( pre_mem_pipeline[pms][i].pc, fout ); if( mask & 0x10 ) { - if ( ( shader->pre_mem_pipeline[pms][i].op == LOAD_OP || - shader->pre_mem_pipeline[pms][i].op == STORE_OP ) && print_mem ) - fprintf(fout, " mem: 0x%016llx", shader->pre_mem_pipeline[pms][i].memreqaddr); + if ( ( pre_mem_pipeline[pms][i].op == LOAD_OP || + pre_mem_pipeline[pms][i].op == STORE_OP ) && print_mem ) + fprintf(fout, " mem: 0x%016llx", pre_mem_pipeline[pms][i].memreqaddr); } fprintf(fout, "\n"); } @@ -3564,158 +2769,134 @@ void shader_print_pre_mem_stages(shader_core_ctx_t *shader, FILE *fout, int prin const char * ptx_get_fname( unsigned PC ); -void shader_display_pipeline(shader_core_ctx_t *shader, FILE *fout, int print_mem, int mask ) +void shader_core_ctx::display_pdom_state(FILE *fout, int mask ) { - // call this function from within gdb to print out status of pipeline - // if you encounter a bug, or to visualize pipeline operation - // (this is a good way to "verify" your pipeline model makes sense!) + if ( (mask & 4) && m_config->model == POST_DOMINATOR ) { + fprintf(fout,"warp status:\n"); + unsigned n = m_config->n_thread_per_shader / m_config->warp_size; + for (unsigned i=0; i < n; i++) { + unsigned nactive = 0; + for (unsigned j=0; j<m_config->warp_size; j++ ) { + unsigned tid = i*m_config->warp_size + j; + int done = ptx_thread_done(tid); + nactive += (ptx_thread_done(tid)?0:1); + if ( done && (mask & 8) ) { + unsigned done_cycle = ptx_thread_donecycle( m_thread[tid].m_functional_model_thread_state ); + if ( done_cycle ) { + printf("\n w%02u:t%03u: done @ cycle %u", i, tid, done_cycle ); + } + } + } + if ( nactive == 0 ) { + continue; + } + m_pdom_warp[i]->print(fout); + } + fprintf(fout,"\n"); + } +} +void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) +{ fprintf(fout, "=================================================\n"); - fprintf(fout, "shader %u at cycle %Lu+%Lu (%u threads running)\n", shader->sid, - gpu_tot_sim_cycle, gpu_sim_cycle, shader->not_completed); + fprintf(fout, "shader %u at cycle %Lu+%Lu (%u threads running)\n", m_sid, + gpu_tot_sim_cycle, gpu_sim_cycle, m_not_completed); fprintf(fout, "=================================================\n"); - if ( (mask & 4) && shader->model == POST_DOMINATOR ) { - fprintf(fout,"warp status:\n"); - unsigned n = shader->n_threads / warp_size; - for (unsigned i=0; i < n; i++) { - unsigned nactive = 0; - for (unsigned j=0; j<warp_size; j++ ) { - unsigned tid = i*warp_size + j; - int done = ptx_thread_done( shader->thread[tid].ptx_thd_info ); - nactive += (ptx_thread_done( shader->thread[tid].ptx_thd_info )?0:1); - if ( done && (mask & 8) ) { - unsigned done_cycle = ptx_thread_donecycle( shader->thread[tid].ptx_thd_info ); - if ( done_cycle ) { - printf("\n w%02u:t%03u: done @ cycle %u", i, tid, done_cycle ); - } - } - } - if ( nactive == 0 ) { - continue; - } - pdom_warp_ctx_t *warp=&(shader->pdom_warp[i]); - for ( int k=0; k <= warp->m_stack_top; k++ ) { - if ( k==0 ) { - fprintf(fout, "w%02d (%2u thds active): %2u ", i, nactive, k ); - } else { - fprintf(fout, " %2u ", k ); - } - for (unsigned m=1,j=0; j<warp_size; j++, m<<=1) - fprintf(fout, "%c", ((warp->m_active_mask[k] & m)?'1':'0') ); - fprintf(fout, " pc: %4u", warp->m_pc[k] ); - if ( warp->m_recvg_pc[k] == (unsigned)-1 ) { - fprintf(fout," rp: ---- cd: %2u ", warp->m_calldepth[k] ); - } else { - fprintf(fout," rp: %4u cd: %2u ", warp->m_recvg_pc[k], warp->m_calldepth[k] ); - } - if ( warp->m_branch_div_cycle[k] != 0 ) { - fprintf(fout," bd@%6u ", (unsigned) warp->m_branch_div_cycle[k] ); - } else { - fprintf(fout," " ); - } - //fprintf(fout," func=\'%s\' ", ptx_get_fname( warp->m_pc[k] ) ); - ptx_print_insn( warp->m_pc[k], fout ); - fprintf(fout,"\n"); - } - } - fprintf(fout,"\n"); - } - - if ( mask & 0x20 ) { - fprintf(fout, "TS/IF = "); - shader_print_stage(shader, TS_IF, fout, warp_size, print_mem, mask); - } + if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) + display_pdom_state(fout,mask); - fprintf(fout, "IF/ID = "); - shader_print_stage(shader, IF_ID, fout, pipe_simd_width, print_mem, mask ); + if (!strcmp("GT200",m_config->pipeline_model) ) { + dump_istream_state(fout); + fprintf(fout,"\n"); - if (gpgpu_operand_collector) - shader->m_opndcoll_new.dump(fout); - - if (shader->using_rrstage) { - fprintf(fout, "ID/RR = "); - shader_print_stage(shader, ID_RR, fout, pipe_simd_width, print_mem, mask); + fprintf(fout, "IF/ID = "); + if( !m_inst_fetch_buffer.m_valid ) + fprintf(fout,"bubble\n"); + else { + fprintf(fout,"w%2u : pc = 0x%x, nbytes = %u\n", + m_inst_fetch_buffer.m_warp_id, + m_inst_fetch_buffer.m_pc, + m_inst_fetch_buffer.m_nbytes ); + } + fprintf(fout,"\nibuffer status:\n"); + for( unsigned i=0; i<m_config->max_warps_per_shader; i++) { + if( !m_warp[i].ibuffer_empty() ) + m_warp[i].print_ibuffer(fout); + } + fprintf(fout,"\n"); + display_pdom_state(fout,mask); } - fprintf(fout, "ID/EX = "); - shader_print_stage(shader, ID_EX, fout, pipe_simd_width, print_mem, mask); - - shader_print_pre_mem_stages(shader, fout, print_mem, mask); + m_scoreboard->printContents(); - if (!gpgpu_pre_mem_stages) - fprintf(fout, "EX/MEM= "); + if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { + if ( mask & 0x20 ) { + fprintf(fout, "TS/IF = "); + print_stage(TS_IF, fout, print_mem, mask); + } + fprintf(fout, "IF/ID = "); + print_stage(IF_ID, fout, print_mem, mask ); + } + if (m_config->gpgpu_operand_collector) { + fprintf(fout,"ID/OC (SP) = "); + print_stage(ID_OC, fout, print_mem, mask); + fprintf(fout,"ID/OC (SFU) = "); + print_stage(ID_OC_SFU, fout, print_mem, mask); + m_operand_collector.dump(fout); + } + if (m_config->m_using_dwf_rrstage) { + fprintf(fout, "ID/RR = "); + print_stage(ID_RR, fout, print_mem, mask); + } + if (!strcmp("GT200",m_config->pipeline_model) ) + fprintf(fout, "ID/EX (SP) = "); else - fprintf(fout, "PM/MEM= "); - shader_print_stage(shader, EX_MM, fout, pipe_simd_width, print_mem, mask); - - fprintf(fout, "MEM/WB= "); - shader_print_stage(shader, MM_WB, fout, pipe_simd_width, print_mem, mask); - - fprintf(fout, "\n"); -} - -void shader_dump_thread_state(shader_core_ctx_t *shader, FILE *fout ) -{ - fprintf( fout, "\n"); - for ( unsigned w = 0; w < gpu_n_thread_per_shader/warp_size; w++ ) { - int tid = w*warp_size; - if ( shader->warp[w].n_completed < (unsigned)warp_size ) { - fprintf( fout, " %u:%3u fetch state = c:%u a4f:%u bw:%u (completed: ", shader->sid, tid, - shader->warp[w].n_completed, - shader->warp[w].n_avail4fetch, - shader->warp[w].n_waiting_at_barrier ); - - for ( unsigned i = tid; i < (w+1)*warp_size; i++ ) { - if ( gpgpu_cuda_sim && ptx_thread_done(shader->thread[i].ptx_thd_info) ) { - fprintf(fout,"1"); - } else { - fprintf(fout,"0"); - } - if ( (((i+1)%4) == 0) && (i+1) < (w+1)*warp_size ) { - fprintf(fout,","); - } - } - fprintf(fout,")\n"); - } + fprintf(fout, "ID/EX = "); + print_stage(ID_EX, fout, print_mem, mask); + if (!strcmp("GT200",m_config->pipeline_model) ) { + fprintf(fout, "ID/EX (SFU) = "); + print_stage(OC_EX_SFU, fout, print_mem, mask); } + print_pre_mem_stages(fout, print_mem, mask); + if (!m_config->gpgpu_pre_mem_stages) + fprintf(fout, "EX/MEM = "); + else + fprintf(fout, "PM/MEM = "); + print_stage(EX_MM, fout, print_mem, mask); + fprintf(fout, "MEM/WB = "); + print_stage(MM_WB, fout, print_mem, mask); + fprintf(fout, "\n"); + mshr_print(fout,0); } -void shader_dp(shader_core_ctx_t *shader, int print_mem) { - shader_display_pipeline(shader, stdout, print_mem, 7 ); -} - - -unsigned int max_cta_per_shader( shader_core_ctx_t *shader) +unsigned int shader_core_ctx::max_cta( class function_info *kernel ) { - unsigned int result; unsigned int padded_cta_size; - padded_cta_size = ptx_sim_cta_size(); - if (padded_cta_size%warp_size) { - padded_cta_size = ((padded_cta_size/warp_size)+1)*(warp_size); - //printf("padded_cta_size=%u\n", padded_cta_size); - } + padded_cta_size = m_gpu->the_kernel().threads_per_cta(); + if (padded_cta_size%m_config->warp_size) + padded_cta_size = ((padded_cta_size/m_config->warp_size)+1)*(m_config->warp_size); //Limit by n_threads/shader - unsigned int result_thread = shader->n_threads / padded_cta_size; + unsigned int result_thread = m_config->n_thread_per_shader / padded_cta_size; - const struct gpgpu_ptx_sim_kernel_info *kernel_info = ptx_sim_kernel_info(); + const struct gpgpu_ptx_sim_kernel_info *kernel_info = ptx_sim_kernel_info(kernel); //Limit by shmem/shader unsigned int result_shmem = (unsigned)-1; if (kernel_info->smem > 0) - result_shmem = shader->shmem_size / kernel_info->smem; + result_shmem = m_config->gpgpu_shmem_size / kernel_info->smem; //Limit by register count, rounded up to multiple of 4. unsigned int result_regs = (unsigned)-1; if (kernel_info->regs > 0) - result_regs = shader->n_registers / (padded_cta_size * ((kernel_info->regs+3)&~3)); + result_regs = m_config->gpgpu_shader_registers / (padded_cta_size * ((kernel_info->regs+3)&~3)); //Limit by CTA - unsigned int result_cta = shader->n_cta; + unsigned int result_cta = m_config->max_cta_per_core; - result = result_thread; + unsigned result = result_thread; result = gs_min2(result, result_shmem); result = gs_min2(result, result_regs); result = gs_min2(result, result_cta); @@ -3732,114 +2913,49 @@ unsigned int max_cta_per_shader( shader_core_ctx_t *shader) } if (result < 1) { - printf ("Error: max_cta_per_shader(\"%s\") returning %d. Kernel requires more resources than shader has?\n", shader->name, result); + printf ("Error: max_cta_per_shader(\"%s\") returning %d. Kernel requires more resources than shader has?\n", m_name, result); abort(); } return result; } -void shader_cycle( shader_core_ctx_t *shader, - unsigned int shader_number, - int grid_num ) +void shader_core_ctx::cycle_gt200() { - if (gpgpu_operand_collector) - shader_opnd_collect_write(shader); - shader_writeback(shader, shader_number, grid_num); - shader_memory(shader, shader_number); - if (gpgpu_pre_mem_stages) // for modeling deeper pipelines - shader_pre_memory(shader, shader_number); - shader_execute(shader, shader_number); - if (shader->using_rrstage) { - // Model register bank conflicts as in - // Fung et al. MICRO'07 / ACM TACO'09 papers. - shader_preexecute (shader, shader_number); - } - if (gpgpu_operand_collector) - shader_opnd_collect_read(shader); - shader_decode (shader, shader_number, grid_num); - shader_fetch (shader, shader_number, grid_num); + clear_stage(m_pipeline_reg[WB_RT]); + writeback(); + memory(); + execute(); + m_operand_collector.step(m_pipeline_reg[ID_OC],m_pipeline_reg[ID_OC_SFU]); + decode_new(); + fetch_new(); } -// performance counter that are not local to one shader -void shader_print_accstats( FILE* fout ) +void shader_core_ctx::cycle() { - fprintf(fout, "gpgpu_n_load_insn = %d\n", gpgpu_n_load_insn); - fprintf(fout, "gpgpu_n_store_insn = %d\n", gpgpu_n_store_insn); - fprintf(fout, "gpgpu_n_shmem_insn = %d\n", gpgpu_n_shmem_insn); - fprintf(fout, "gpgpu_n_tex_insn = %d\n", gpgpu_n_tex_insn); - fprintf(fout, "gpgpu_n_const_mem_insn = %d\n", gpgpu_n_const_insn); - fprintf(fout, "gpgpu_n_param_mem_insn = %d\n", gpgpu_n_param_insn); - - fprintf(fout, "gpgpu_n_shmem_bkconflict = %d\n", gpgpu_n_shmem_bkconflict); - fprintf(fout, "gpgpu_n_cache_bkconflict = %d\n", gpgpu_n_cache_bkconflict); - - fprintf(fout, "gpgpu_n_intrawarp_mshr_merge = %d\n", gpgpu_n_intrawarp_mshr_merge); - fprintf(fout, "gpgpu_n_cmem_portconflict = %d\n", gpgpu_n_cmem_portconflict); - - fprintf(fout, "gpgpu_n_writeback_l1_miss = %d\n", writeback_l1_miss); - - fprintf(fout, "gpgpu_n_partial_writes = %d\n", gpgpu_n_partial_writes); - - fprintf(fout, "gpgpu_stall_shd_mem[c_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][BK_CONF]); - fprintf(fout, "gpgpu_stall_shd_mem[c_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[c_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[t_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[t_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[s_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[S_MEM][BK_CONF]); - fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][bk_conf] = %d\n", - gpu_stall_shd_mem_breakdown[G_MEM_LD][BK_CONF] + - gpu_stall_shd_mem_breakdown[G_MEM_ST][BK_CONF] + - gpu_stall_shd_mem_breakdown[L_MEM_LD][BK_CONF] + - gpu_stall_shd_mem_breakdown[L_MEM_ST][BK_CONF] - ); // coalescing stall at data cache - fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][coal_stall] = %d\n", - gpu_stall_shd_mem_breakdown[G_MEM_LD][COAL_STALL] + - gpu_stall_shd_mem_breakdown[G_MEM_ST][COAL_STALL] + - gpu_stall_shd_mem_breakdown[L_MEM_LD][COAL_STALL] + - gpu_stall_shd_mem_breakdown[L_MEM_ST][COAL_STALL] - ); // coalescing stall + bank conflict at data cache - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_CACHE_RSRV_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_CACHE_RSRV_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_CACHE_RSRV_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_CACHE_RSRV_FAIL]); - - fprintf(fout, "gpu_reg_bank_conflict_stalls = %d\n", gpu_reg_bank_conflict_stalls); - - if (warp_occ_detailed) { - int n_warp = gpu_n_thread_per_shader / warp_size; - - for (unsigned s = 0; s<gpu_n_shader; s++) - for (int w = 0; w<n_warp; w++) { - fprintf(fout, "wod[%d][%d]=", s, w); - for (unsigned t = 0; t<warp_size; t++) { - fprintf(fout, "%d ", warp_occ_detailed[s * n_warp + w][t]); - } - fprintf(fout, "\n"); - } + clear_stage(m_pipeline_reg[WB_RT]); + writeback(); + memory(); + if (m_config->gpgpu_pre_mem_stages) // for modeling deeper pipelines + pre_memory(); + execute(); + if (m_config->m_using_dwf_rrstage) { + preexecute(); } + if (m_config->gpgpu_operand_collector) + m_operand_collector.step(m_pipeline_reg[ID_OC]); + decode(); + fetch(); } // Flushes all content of the cache to memory -void shader_cache_flush(shader_core_ctx_t* sc) +void shader_core_ctx::cache_flush() { unsigned int i; unsigned int set; unsigned long long int flush_addr; - shd_cache_t *cp = sc->L1cache; + shd_cache_t *cp = m_L1D; shd_cache_line_t *pline; for (i=0; i<cp->nset*cp->assoc; i++) { @@ -3848,7 +2964,7 @@ void shader_cache_flush(shader_core_ctx_t* sc) if ((pline->status & (DIRTY|VALID)) == (DIRTY|VALID)) { flush_addr = pline->addr; - sc->fq_push(flush_addr, sc->L1cache->line_sz, 1, NO_PARTIAL_WRITE, sc->sid, 0, NULL, 0, GLOBAL_ACC_W, -1); + fq_push(flush_addr, m_L1D->line_sz, 1, NO_PARTIAL_WRITE, 0, NULL, 0, GLOBAL_ACC_W, -1); pline->status &= ~VALID; pline->status &= ~DIRTY; @@ -3889,15 +3005,22 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() _outmatch[j] = -1; for( unsigned i=0; i<m_num_banks; i++) { - for( unsigned j=0; j<m_num_collectors; j++) + for( unsigned j=0; j<m_num_collectors; j++) { + assert( i < (unsigned)_inputs ); + assert( j < (unsigned)_outputs ); _request[i][j] = 0; + } if( !m_queue[i].empty() ) { const op_t &op = m_queue[i].front(); int oc_id = op.get_oc_id(); + assert( i < (unsigned)_inputs ); + assert( oc_id < _outputs ); _request[i][oc_id] = 1; } - if( m_allocated_bank[i].is_write() ) + if( m_allocated_bank[i].is_write() ) { + assert( i < (unsigned)_inputs ); _inmatch[i] = 0; // write gets priority + } } ///// wavefront allocator from booksim... ---> @@ -3914,7 +3037,9 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() ( _outmatch[output] == -1 ) && ( _request[input][output]/*.label != -1*/ ) ) { // Grant! + assert( input < _inputs ); _inmatch[input] = output; + assert( output < _outputs ); _outmatch[output] = input; } @@ -3939,24 +3064,6 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() } } - -/* - for( unsigned c=0; c < m_num_collectors; c++ ) { - unsigned cu = (m_last_cu+c+1)%m_num_collectors; - for( unsigned b=0; b < m_num_banks; b++ ) { - unsigned bank = (m_allocator_rr_head[cu]+b+1)%m_num_banks; - if( (!m_queue[bank].empty()) && m_allocated_bank[bank].is_free() ) { - op_t &op = m_queue[bank].front(); - result.push_back(op); - m_allocated_bank[bank].alloc_read(op); - m_queue[bank].pop_front(); - m_allocator_rr_head[cu] = bank; - m_last_cu = cu; - break; // skip to next collector unit - } - } - } -*/ return result; } @@ -4042,7 +3149,7 @@ void barrier_set_t::warp_exit( unsigned warp_id ) } // assertions -bool barrier_set_t::warp_waiting_at_barrier( unsigned warp_id ) +bool barrier_set_t::warp_waiting_at_barrier( unsigned warp_id ) const { return m_warp_at_barrier.test(warp_id); } @@ -4075,11 +3182,37 @@ void shader_core_ctx::warp_exit( unsigned warp_id ) m_barriers.warp_exit( warp_id ); } -bool shader_core_ctx::warp_waiting_at_barrier( unsigned warp_id ) +bool shader_core_ctx::warp_waiting_at_barrier( unsigned warp_id ) const { return m_barriers.warp_waiting_at_barrier(warp_id); } +void shader_core_ctx::set_at_memory_barrier( unsigned warp_id ) +{ + m_warp[warp_id].set_membar(); +} + +bool shader_core_ctx::warp_waiting_at_mem_barrier( unsigned warp_id ) +{ + if( !m_warp[warp_id].get_membar() ) + return false; + if( !m_scoreboard->pendingWrites(warp_id) ) { + m_warp[warp_id].clear_membar(); + return false; + } + return true; +} + +bool shader_core_ctx::warp_waiting_for_atomics( unsigned warp_id ) const +{ + return m_warp[warp_id].get_n_atomic()>0; +} + +gpgpu_sim *shader_core_ctx::get_gpu() +{ + return m_gpu; +} + void shader_core_ctx::allocate_barrier( unsigned cta_id, warp_set_t warps ) { m_barriers.allocate_barrier(cta_id,warps); @@ -4090,36 +3223,384 @@ void shader_core_ctx::deallocate_barrier( unsigned cta_id ) m_barriers.deallocate_barrier(cta_id); } +void shader_core_ctx::decrement_atomic_count( unsigned wid ) +{ + assert( m_warp[wid].get_n_atomic() > 0 ); + m_warp[wid].dec_n_atomic(); +} + +bool shd_warp_t::done() +{ + return get_n_completed() == m_warp_size; +} + +bool shd_warp_t::waiting() +{ + if ( done() ) { + // waiting to be initialized with a kernel + return true; + } else if ( m_shader->warp_waiting_at_barrier(m_warp_id) ) { + // waiting for other warps in CTA to reach barrier + return true; + } else if ( m_shader->warp_waiting_at_mem_barrier(m_warp_id) ) { + // waiting for memory barrier + return true; + } else if ( m_shader->warp_waiting_for_atomics(m_warp_id) ) { + // waiting for atomic operation to complete at memory: + // this stall is not required for accurate timing model, but rather we + // stall here since if a call/return instruction occurs in the meantime + // the functional execution of the atomic when it hits DRAM can cause + // the wrong register to be read. + return true; + } + return false; +} + +void shd_warp_t::print( FILE *fout ) const +{ + if ( n_completed < m_warp_size ) { + fprintf( fout, "w%02u npc: 0x%04x, done:%2u a4f:%2u, i:%u s:%u a:%u b:%2u, (done: ", + m_warp_id, + m_next_pc, + n_completed, + n_avail4fetch, + m_inst_in_pipeline, + m_stores_outstanding, + m_n_atomic, + n_waiting_at_barrier ); + for (unsigned i = m_warp_id*m_warp_size; i < (m_warp_id+1)*m_warp_size; i++ ) { + if ( m_shader->ptx_thread_done(i) ) fprintf(fout,"1"); + else fprintf(fout,"0"); + if ( (((i+1)%4) == 0) && (i+1) < (m_warp_id+1)*m_warp_size ) + fprintf(fout,","); + } + fprintf(fout,") "); + fprintf(fout," last fetched @ %5llu", m_last_fetch); + if( m_imiss_pending ) + fprintf(fout," i-miss pending"); + fprintf(fout,"\n"); + } +} + +void shd_warp_t::print_ibuffer( FILE *fout ) const +{ + fprintf(fout," ibuffer[%2u] : ", m_warp_id ); + for( unsigned i=0; i < IBUFFER_SIZE; i++) { + const inst_t *inst = m_ibuffer[i]; + if( inst ) inst->print_insn(fout); + else fprintf(fout," <empty> "); + } + fprintf(fout,"\n"); +} + +pdom_warp_ctx_t::pdom_warp_ctx_t( unsigned wid, class shader_core_ctx *shdr ) +{ + m_warp_id=wid; + m_shader=shdr; + m_warp_size=m_shader->get_config()->warp_size; + m_stack_top = 0; + m_pc = (address_type*)calloc(m_warp_size * 2, sizeof(address_type)); + m_calldepth = (unsigned int*)calloc(m_warp_size * 2, sizeof(unsigned int)); + m_active_mask = (unsigned int*)calloc(m_warp_size * 2, sizeof(unsigned int)); + m_recvg_pc = (address_type*)calloc(m_warp_size * 2, sizeof(address_type)); + m_branch_div_cycle = (unsigned long long *)calloc(m_warp_size * 2, sizeof(unsigned long long )); + reset(); +} + +void pdom_warp_ctx_t::reset() +{ + m_stack_top = 0; + memset(m_pc, -1, m_warp_size * 2 * sizeof(address_type)); + memset(m_calldepth, 0, m_warp_size * 2 * sizeof(unsigned int)); + memset(m_active_mask, 0, m_warp_size * 2 * sizeof(unsigned int)); + memset(m_recvg_pc, -1, m_warp_size * 2 * sizeof(address_type)); + memset(m_branch_div_cycle, 0, m_warp_size * 2 * sizeof(unsigned long long )); +} + +void pdom_warp_ctx_t::launch( address_type start_pc, unsigned active_mask ) +{ + reset(); + m_pc[0] = start_pc; + m_calldepth[0] = 1; + m_active_mask[0] = active_mask; +} + +unsigned pdom_warp_ctx_t::get_active_mask() const +{ + return m_active_mask[m_stack_top]; +} + +void mshr_entry::init( new_addr_type address, bool wr, memory_space_t space, unsigned warp_id ) +{ + static unsigned next_request_uid = 1; + m_request_uid = next_request_uid++; + m_status = INITIALIZED; + m_addr = address; + m_mf = NULL; + m_merged_on_other_reqest = false; + m_merged_requests =NULL; + m_iswrite = wr; + m_isinst = space==instruction_space; + m_islocal = is_local(space); + m_isconst = is_const(space); + m_istexture = space==tex_space; + m_insts.clear(); + m_warp_id = warp_id; +} + +void mshr_entry::set_status( enum mshr_status status ) +{ + mshr_entry * req = this; + while (req) { + req->m_status = status; + req = req->m_merged_requests; + } +#if DEBUGL1MISS + printf("cycle %d Addr %x %d \n",gpu_sim_cycle,CACHE_TAG_OF_64(m_addr),status); +#endif +} + +void mshr_entry::print(FILE *fp, unsigned mask) const +{ + if ( mask & 0x100 ) { + fprintf(fp, "MSHR(%u): w%2u req uid=%5u, %s (0x%llx) merged:%d status:%s ", + m_id, + m_warp_id, + m_request_uid, + (m_iswrite)? "store" : "load ", + m_addr, + (m_merged_requests != NULL || m_merged_on_other_reqest), + MSHR_Status_str[m_status]); + if ( m_mf ) + ptx_print_insn( m_mf->pc, fp ); + fprintf(fp,"\n"); + if ( mask & 0x200 ) { + for (unsigned i = 0; i < m_insts.size(); i++) { + fprintf(fp,"\tthread: UID:%d HW:%d ReqAddr:0x%llx\n", + m_insts[i].uid, m_insts[i].hw_thread_id, m_insts[i].memreqaddr); + } + } + } +} + void opndcoll_rfu_t::init( unsigned num_collectors_alu, unsigned num_collectors_sfu, unsigned num_banks, - const shader_core_ctx *shader ) + shader_core_ctx *shader, + inst_t **alu_port, + inst_t **sfu_port ) { - unsigned num_alu_cu = gpgpu_operand_collector_num_units; - unsigned num_sfu_cu = gpgpu_operand_collector_num_units_sfu; - m_num_collectors = num_alu_cu+num_sfu_cu; + m_num_collectors = num_collectors_alu+num_collectors_sfu; m_shader=shader; m_arbiter.init(m_num_collectors,num_banks); - m_alu_port = shader->pipeline_reg[ID_EX]; - m_sfu_port = shader->pipeline_reg[OC_EX_SFU]; + m_alu_port = alu_port; + m_sfu_port = sfu_port; - m_dispatch_units[ m_alu_port ].init( num_alu_cu ); - m_dispatch_units[ m_sfu_port ].init( num_sfu_cu ); + m_dispatch_units[ m_alu_port ].init( num_collectors_alu ); + m_dispatch_units[ m_sfu_port ].init( num_collectors_sfu ); m_num_banks = num_banks; + + m_bank_warp_shift = 0; + m_warp_size = shader->get_config()->warp_size; + m_bank_warp_shift = (unsigned)(int) (log(m_warp_size+0.5) / log(2.0)); + assert( (m_bank_warp_shift == 5) || (m_warp_size != 32) ); + m_cu = new collector_unit_t[m_num_collectors]; unsigned c=0; - for(; c<num_alu_cu; c++) { - m_cu[c].init(c,m_alu_port); + for(; c<num_collectors_alu; c++) { + m_cu[c].init(c,m_alu_port,num_banks,m_bank_warp_shift,m_warp_size,this); m_free_cu[m_alu_port].push_back(&m_cu[c]); m_dispatch_units[m_alu_port].add_cu(&m_cu[c]); } for(; c<m_num_collectors; c++) { - m_cu[c].init(c,m_sfu_port); + m_cu[c].init(c,m_sfu_port,num_banks,m_bank_warp_shift,m_warp_size,this); m_free_cu[m_sfu_port].push_back(&m_cu[c]); m_dispatch_units[m_sfu_port].add_cu(&m_cu[c]); } } + +bool opndcoll_rfu_t::writeback( inst_t *warp ) +{ + // prefer not to stall writeback + inst_t *fvt=m_shader->first_valid_thread(warp); + if (!fvt) + return true; // nothing to do + return writeback(*fvt); +} + +int register_bank(int regnum, int tid, unsigned num_banks, unsigned bank_warp_shift) +{ + int bank = regnum; + if (bank_warp_shift) + bank += tid >> bank_warp_shift; + return bank % num_banks; +} + +bool opndcoll_rfu_t::writeback( const inst_t &fvt ) +{ + int tid = fvt.hw_thread_id; + assert( tid >= 0 ); // must be a valid instruction + std::list<unsigned> regs = m_shader->get_regs_written(fvt); + std::list<unsigned>::iterator r; + unsigned last_reg = -1; + unsigned n=0; + for( r=regs.begin(); r!=regs.end();r++,n++ ) { + unsigned reg = *r; + unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift); + if( m_arbiter.bank_idle(bank) ) { + m_arbiter.allocate_bank_for_write(bank,op_t(&fvt,reg,m_num_banks,m_bank_warp_shift)); + } else { + return false; + } + last_reg=reg; + } + return true; +} + +void opndcoll_rfu_t::dispatch_ready_cu() +{ + port_to_du_t::iterator p; + for( p=m_dispatch_units.begin(); p!=m_dispatch_units.end(); ++p ) { + inst_t **port = p->first; + if( !m_shader->pipeline_regster_empty(*port) ) + continue; + dispatch_unit_t &du = p->second; + collector_unit_t *cu = du.find_ready(); + if( cu ) { + cu->dispatch(); + m_free_cu[port].push_back(cu); + } + } +} + +void opndcoll_rfu_t::allocate_cu( inst_t *&id_oc_reg ) +{ + inst_t *fvi = m_shader->first_valid_thread(id_oc_reg); + if( fvi ) { + inst_t **port = NULL; + if( fvi->op == SFU_OP ) + port = m_sfu_port; + else + port = m_alu_port; + if( !m_free_cu[port].empty() ) { + collector_unit_t *cu = m_free_cu[port].back(); + m_free_cu[port].pop_back(); + cu->allocate(id_oc_reg); + m_arbiter.add_read_requests(cu); + } + } +} + +void opndcoll_rfu_t::allocate_reads() +{ + // process read requests that do not have conflicts + std::list<op_t> allocated = m_arbiter.allocate_reads(); + std::map<unsigned,op_t> read_ops; + for( std::list<op_t>::iterator r=allocated.begin(); r!=allocated.end(); r++ ) { + const op_t &rr = *r; + unsigned reg = rr.get_reg(); + unsigned tid = rr.get_tid(); + unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift); + m_arbiter.allocate_for_read(bank,rr); + read_ops[bank] = rr; + } + std::map<unsigned,op_t>::iterator r; + for(r=read_ops.begin();r!=read_ops.end();++r ) { + op_t &op = r->second; + unsigned cu = op.get_oc_id(); + unsigned operand = op.get_operand(); + assert( cu < m_num_collectors ); + m_cu[cu].collect_operand(operand); + } +} + + +void gpgpu_sim::decrement_atomic_count( unsigned sid, unsigned wid ) +{ + m_sc[sid]->decrement_atomic_count(wid); +} + + +bool opndcoll_rfu_t::collector_unit_t::ready() const +{ + return (!m_free) && m_not_ready.none() && m_rfu->shader_core()->pipeline_regster_empty(*m_port); +} + +void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *shader ) const +{ + if( m_free ) { + fprintf(fp," <free>\n"); + } else { + shader->print_warp(m_warp,fp,0,0); + for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) { + if( m_not_ready.test(i) ) { + std::string r = m_src_op[i].get_reg_string(); + fprintf(fp," '%s' not ready\n", r.c_str() ); + } + } + } +} + +void opndcoll_rfu_t::collector_unit_t::init( unsigned n, + inst_t **port, + unsigned num_banks, + unsigned log2_warp_size, + unsigned warp_size, + opndcoll_rfu_t *rfu ) +{ + m_rfu=rfu; + m_cuid=n; + m_port=port; + m_num_banks=num_banks; + assert(m_warp==NULL); + m_warp = (inst_t*)calloc(sizeof(inst_t),warp_size); + m_rfu->shader_core()->clear_stage(m_warp); + m_bank_warp_shift=log2_warp_size; +} + +void opndcoll_rfu_t::collector_unit_t::allocate( inst_t *&pipeline_reg ) +{ + assert(m_free); + assert(m_not_ready.none()); + m_free = false; + inst_t *fvi = m_rfu->shader_core()->first_valid_thread(pipeline_reg); + if( fvi ) { + m_tid = fvi->hw_thread_id; + m_warp_id = m_tid/m_rfu->shader_core()->get_config()->warp_size; + for( unsigned op=0; op < 4; op++ ) { + int reg_num = fvi->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst + if( reg_num >= 0 ) { // valid register + m_src_op[op] = op_t( this, op, reg_num, m_num_banks, m_bank_warp_shift ); + m_not_ready.set(op); + } else + m_src_op[op] = op_t(); + } + m_rfu->shader_core()->move_warp(m_warp,pipeline_reg); + } +} + +void opndcoll_rfu_t::collector_unit_t::dispatch() +{ + assert( m_not_ready.none() ); + m_rfu->shader_core()->move_warp(*m_port,m_warp); + m_free=true; + for( unsigned i=0; i<MAX_REG_OPERANDS;i++) + m_src_op[i].reset(); +} + +bool shader_core_ctx::ptx_thread_done( unsigned hw_thread_id ) const +{ + assert( hw_thread_id < m_config->n_thread_per_shader ); + ptx_thread_info *thd = m_thread[ hw_thread_id ].m_functional_model_thread_state; + return (thd==NULL) || thd->is_done(); +} + +class ptx_thread_info *shader_core_ctx::get_thread_state( unsigned hw_thread_id ) +{ + assert( hw_thread_id < m_config->n_thread_per_shader ); + return m_thread[ hw_thread_id ].m_functional_model_thread_state; +} diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index 1e62995..44206af 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -72,6 +72,10 @@ #include <set> #include <vector> #include <list> +#include <bitset> +#include <utility> +#include <algorithm> +#include <deque> #include "../cuda-sim/ptx.tab.h" #include "../cuda-sim/dram_callback.h" @@ -82,148 +86,238 @@ #include "dram.h" #include "../abstract_hardware_model.h" #include "scoreboard.h" +#include "mem_fetch.h" +#include "stats.h" #ifndef SHADER_H #define SHADER_H #define NO_OP_FLAG 0xFF -//READ_PACKET_SIZE: bytes: 6 address (flit can specify chanel so this gives up to ~2GB/channel, so good for now), 2 bytes [shaderid + mshrid](14 bits) + req_size(0-2 bits (if req_size variable) - so up to 2^14 = 16384 mshr total +/* READ_PACKET_SIZE: + bytes: 6 address (flit can specify chanel so this gives up to ~2GB/channel, so good for now), + 2 bytes [shaderid + mshrid](14 bits) + req_size(0-2 bits if req_size variable) - so up to 2^14 = 16384 mshr total + */ + #define READ_PACKET_SIZE 8 + //WRITE_PACKET_SIZE: bytes: 6 address, 2 miscelaneous. #define WRITE_PACKET_SIZE 8 -#include <bitset> -const unsigned partial_write_mask_bits = 128; //must be at least size of largest memory access. -typedef std::bitset<partial_write_mask_bits> partial_write_mask_t; - #define WRITE_MASK_SIZE 8 #define NO_PARTIAL_WRITE (partial_write_mask_t()) -//this is used a lot of places where it maybe should be more variable? #define WORD_SIZE 4 //Set a hard limit of 32 CTAs per shader [cuda only has 8] #define MAX_CTA_PER_SHADER 32 -typedef unsigned op_type; - -enum { - NO_RECONVERGE = 0, - POST_DOMINATOR = 1, - MIMD = 2, - DWF = 3, - NUM_SIMD_MODEL -}; - -//Defines number of threads grouped together to be executed together - +class thread_ctx_t { +public: + class ptx_thread_info *m_functional_model_thread_state; + unsigned m_cta_id; // hardware CTA this thread belongs -typedef struct { + // used for controlling fetch + bool m_avail4fetch; // false if instruction from thread is in pipeline + bool m_in_scheduler; // DWF error checking + bool m_waiting_at_barrier; // DWF and MIMD models + bool m_reached_barrier; // DWF only - address_type pc; + // per thread stats (ac stands for accumulative). + unsigned n_insn; + unsigned n_insn_ac; + unsigned n_l1_mis_ac; + unsigned n_l1_mrghit_ac; + unsigned n_l1_access_ac; +}; - op_type op; - memory_space_t space; +class shd_warp_t { +public: + shd_warp_t( class shader_core_ctx *shader, unsigned warp_size) + : m_shader(shader), m_warp_size(warp_size) + { + m_stores_outstanding=0; + m_inst_in_pipeline=0; + reset(); + } + void reset() + { + assert( m_stores_outstanding==0); + assert( m_inst_in_pipeline==0); + m_imiss_pending=false; + m_warp_id=(unsigned)-1; + n_completed = m_warp_size; + n_avail4fetch = n_waiting_at_barrier = 0; + m_n_atomic=0; + m_membar=false; + m_done_exit=false; + m_last_fetch=0; + m_next=0; + for(unsigned i=0;i<IBUFFER_SIZE;i++) + m_ibuffer[i]=NULL; + } + void init( address_type start_pc, unsigned wid, unsigned active ) + { + m_warp_id=wid; + m_next_pc=start_pc; + assert( n_completed >= active ); + assert( n_completed <= m_warp_size); + assert( n_avail4fetch < m_warp_size ); + n_completed -= active; // active threads are not yet completed + n_avail4fetch += active; // number of threads in warp available to be fetched + } - unsigned long long int memreqaddr; - //Each instruction keeps track of which hardware thread it came from - short hw_thread_id; - short wlane; + bool done(); + bool waiting(); - /* reg label of the instruction */ - unsigned out[4]; - unsigned in[4]; - unsigned char is_vectorin; - unsigned char is_vectorout; - int pred; - int ar1, ar2; - int arch_reg[MAX_REG_OPERANDS]; // register number for bank conflict evaluation - unsigned data_size; // what is the size of the word being operated on? - unsigned cycles; // number of cycles taken by current instruction + bool done_exit() const { return m_done_exit; } + void set_done_exit() { m_done_exit=true; } - int reg_bank_access_pending; - int reg_bank_conflict_stall_checked; // flag to turn off register bank conflict checker to avoid double stalling + void print( FILE *fout ) const; + void print_ibuffer( FILE *fout ) const; - unsigned inst_type; + unsigned get_avail4fetch() const { return n_avail4fetch; } + void inc_avail4fetch() { n_avail4fetch++; } + void dec_avail4fetch() { n_avail4fetch--; } - unsigned priority; + unsigned get_n_completed() const { return n_completed; } + void inc_n_completed() { n_completed++; } - unsigned uid; + void set_last_fetch( unsigned long long sim_cycle ) { m_last_fetch=sim_cycle; } - void *ptx_thd_info; - dram_callback_t callback; - unsigned warp_active_mask; - unsigned long long ts_cycle; - unsigned long long if_cycle; - unsigned long long id_cycle; - unsigned long long ex_cycle; - unsigned long long mm_cycle; + unsigned get_n_atomic() const { return m_n_atomic; } + void inc_n_atomic() { m_n_atomic++; } + void dec_n_atomic() { m_n_atomic--; } - bool cache_miss; + void inc_waiting_at_barrier() { n_waiting_at_barrier++; } + void clear_waiting_at_barrier() { n_waiting_at_barrier=0; } -} inst_t; + void set_membar() { m_membar=true; } + void clear_membar() { m_membar=false; } + bool get_membar() const { return m_membar; } + address_type get_pc() const { return m_next_pc; } + void set_next_pc( address_type pc ) { m_next_pc = pc; } -typedef struct { + void ibuffer_fill( unsigned slot, const inst_t *pI ) + { + assert(slot < IBUFFER_SIZE ); + m_ibuffer[slot]=pI; + m_next=0; + } + bool ibuffer_empty() const + { + for( unsigned i=0; i < IBUFFER_SIZE; i++) + if(m_ibuffer[i]) + return false; + return true; + } + void ibuffer_flush() + { + for(unsigned i=0;i<IBUFFER_SIZE;i++) { + if( m_ibuffer[i] ) + dec_inst_in_pipeline(); + m_ibuffer[i]=NULL; + } + } + const inst_t *ibuffer_next() + { + const inst_t *result = m_ibuffer[m_next]; + return result; + } + void ibuffer_free() + { + m_ibuffer[m_next] = NULL; + } + void ibuffer_step() + { + m_next = (m_next+1)%IBUFFER_SIZE; + } + bool imiss_pending() const { return m_imiss_pending!=NULL; } + void set_imiss_pending( class mshr_entry *mshr ) + { + m_imiss_pending=mshr; + } + void clear_imiss_pending() { m_imiss_pending=NULL; } - class ptx_thread_info *ptx_thd_info; // pointer to the functional state of the thread in cuda-sim + bool stores_done() const { return m_stores_outstanding == 0; } + void inc_store_req() { m_stores_outstanding++; } + void dec_store_req() + { + assert( m_stores_outstanding > 0 ); + m_stores_outstanding--; + } - int avail4fetch; // 1 if its instrucion can be fetch into the pipeline, 0 otherwise - int warp_priority; + bool inst_in_pipeline() const { return m_inst_in_pipeline > 0; } - int id; + void inc_inst_in_pipeline() { m_inst_in_pipeline++; } + void dec_inst_in_pipeline() + { + assert( m_inst_in_pipeline > 0 ); + m_inst_in_pipeline--; + } - //unsigned n_completed; // number of threads in warp completed -- set for first thread in each warp - //unsigned n_avail4fetch; // number of threads in warp available to fetch -- set for first thread in each warp - //int n_waiting_at_barrier; // number of threads in warp that have reached the barrier - unsigned in_scheduler; // used by dynamic warp formation for error check +private: + static const unsigned IBUFFER_SIZE=2; + class shader_core_ctx *m_shader; + unsigned m_warp_id; + unsigned m_warp_size; - int m_waiting_at_barrier; - int m_reached_barrier; + address_type m_next_pc; + unsigned n_completed; // number of threads in warp completed + unsigned n_avail4fetch; // number of threads in warp available to fetch - unsigned n_insn; - unsigned n_insn_ac; - unsigned n_l1_mis_ac, - n_l1_mrghit_ac, - n_l1_access_ac; //used to collect "per thread" l1 miss statistics - // ac stands for accumulative. - unsigned cta_id; // which hardware CTA does this thread belong to? -} thread_ctx_t; + class mshr_entry *m_imiss_pending; + + const inst_t *m_ibuffer[IBUFFER_SIZE]; + unsigned m_next; + + int n_waiting_at_barrier; // number of threads in warp that have reached the barrier + unsigned m_n_atomic; // number of outstanding atomic operations + bool m_membar; // if true, warp is waiting at memory barrier -struct shd_warp_t -{ - shd_warp_t(unsigned warp_size){reset(warp_size); assert(warp_size <= bitset_size);} - void reset(unsigned warp_size){n_completed = warp_size; n_avail4fetch = n_waiting_at_barrier = 0; threads_completed.reset(); threads_functionally_executed.reset();} + bool m_done_exit; // true once thread exit has been registered for threads in this warp - unsigned wid; - unsigned n_completed; // number of threads in warp completed - unsigned n_avail4fetch; // number of threads in warp available to fetch - int n_waiting_at_barrier; // number of threads in warp that have reached the barrier + unsigned long long m_last_fetch; - const static unsigned bitset_size = 32; - std::bitset<bitset_size> threads_completed; - std::bitset<bitset_size> threads_functionally_executed; + unsigned m_stores_outstanding; // number of store requests sent but not yet acknowledged + unsigned m_inst_in_pipeline; }; inline unsigned hw_tid_from_wid(unsigned wid, unsigned warp_size, unsigned i){return wid * warp_size + i;}; inline unsigned wid_from_hw_tid(unsigned tid, unsigned warp_size){return tid/warp_size;}; -typedef struct { - - int m_stack_top; +// bounded stack that implements pdom reconvergence (see MICRO'07 paper) +class pdom_warp_ctx_t { +public: + pdom_warp_ctx_t( unsigned wid, class shader_core_ctx *shdr ); - address_type *m_pc; - unsigned int *m_active_mask; - address_type *m_recvg_pc; - unsigned int *m_calldepth; + void reset(); + void launch( address_type start_pc, unsigned active_mask ); + void pdom_update_warp_mask(); - unsigned long long *m_branch_div_cycle; + unsigned get_active_mask() const; + void get_pdom_stack_top_info( unsigned *pc, unsigned *rpc ); + unsigned get_rp() const; + void print(FILE*fp) const; -} pdom_warp_ctx_t; // bounded stack that implements pdom reconvergence (see MICRO'07 paper) +private: + unsigned m_warp_id; + class shader_core_ctx *m_shader; + unsigned m_stack_top; + unsigned m_warp_size; + + address_type *m_pc; + unsigned int *m_active_mask; + address_type *m_recvg_pc; + unsigned int *m_calldepth; + + unsigned long long *m_branch_div_cycle; +}; enum mshr_status { INITIALIZED = 0, + INVALID, IN_ICNT2MEM, IN_CBTOL2QUEUE, IN_L2TODRAMQUEUE, @@ -257,78 +351,113 @@ enum mem_req_stat { NUM_MEM_REQ_STAT }; #include <vector> -typedef struct mshr_entry_t { -#ifdef _GLIBCXX_DEBUG - //satisfy cxx debug conditions on iterators, needs to be nonsingular to copy, which messes completely with structures containing them. - mshr_entry_t(){ - static std::vector<mshr_entry_t> dummy_vector; - this_mshr = dummy_vector.begin(); //initialize it to something nonsingular so it can be copied. - } -#endif -private: - friend class mshr_shader_unit; - std::vector<mshr_entry_t>::iterator this_mshr; //to ease tracking and update. -public: - unsigned request_uid; - - /* memory address of the data */ - unsigned long long int addr; - - // instructions are stored here. - std::vector<inst_t> insts; - - /* Current stage of the load: fetched or not? */ - bool fetched(){return status == FETCHED;}; - - bool iswrite; - - bool merged_on_other_reqest; //true if waiting for another mshr - this mshr doesn't send a memory request - struct mshr_entry_t *merged_requests; //mshrs waiting on this mshr - enum mshr_status status; - - void *mf; // link to corresponding memory fetch structure - - //unsigned space; //does below. - bool istexture; //if it's a request from the texture cache - bool isconst; //if it's a request from the constant cache - bool islocal; //if it's a request to the local memory of a thread +class mshr_entry { +public: + mshr_entry() + { + m_status = INVALID; + m_merged_requests=NULL; + m_mf=NULL; + m_id=0; + } + void set_id( unsigned n ) { m_id = n; } + void init( new_addr_type address, bool wr, memory_space_t space, unsigned warp_id ); + void clear() { m_insts.clear(); } + void set_mf( class mem_fetch *mf ) { m_mf=mf; } + void add_inst( inst_t inst ) { m_insts.push_back(inst); } + void set_status( enum mshr_status status ); + void merge( mshr_entry *mshr ) + { + //merge this request; + m_merged_requests = mshr; + mshr->m_merged_on_other_reqest = true; + } - bool wt_no_w2cache; //in write_through, sometimes need to prevent writing back returning data into cache, because its been written in the meantime. -} mshr_entry; + dram_callback_t &get_atomic_callback() + { + assert(isatomic()); + return m_insts[0].callback; + } + mshr_entry *get_last_merged() + { + assert(m_status!=INVALID); + mshr_entry *mshr_hit = this; + while (mshr_hit->m_merged_requests) + mshr_hit = mshr_hit->m_merged_requests; + return mshr_hit; + } + void get_insts( std::vector<inst_t> &done_insts ) + { + done_insts.insert(done_insts.end(),m_insts.begin(),m_insts.end()); + } + void add_to_queue( std::deque<mshr_entry*> &q ) + { + // place all merged requests in return queue + mshr_entry *req = this; + while (req) { + q.push_back(req); + req = req->m_merged_requests; + } + } -enum mem_access_type { - GLOBAL_ACC_R = 0, - LOCAL_ACC_R = 1, - CONST_ACC_R = 2, - TEXTURE_ACC_R = 3, - GLOBAL_ACC_W = 4, - LOCAL_ACC_W = 5, - L2_WRBK_ACC = 6, - NUM_MEM_ACCESS_TYPE = 7 + unsigned get_warp_id() const { return m_warp_id; } + bool ismerged() const { return m_merged_on_other_reqest; } + bool fetched() const { return m_status == FETCHED;}; + bool iswrite() const { return m_iswrite; } + bool isinst() const { return m_isinst; } + bool istexture() const { return m_istexture; } + bool isconst() const { return m_isconst; } + bool islocal() const { return m_islocal; } + bool has_inst() const { return m_insts.size()>0; } + unsigned num_inst() const { return m_insts.size(); } + inst_t &get_inst(unsigned n) + { + assert(m_status!=INVALID&&m_insts.size()>0); + return m_insts[n]; + } + unsigned get_insts_uid() const + { + assert(m_status!=INVALID&&m_insts.size()>0); + return m_insts[0].uid; + } + bool isatomic() const + { + assert(m_status!=INVALID); + if( isinst() ) + return false; + assert(m_insts.size()>0); + return (m_insts[0].callback.function != NULL); + } + new_addr_type get_addr() const { return m_addr; } + void print(FILE *fp, unsigned mask) const; + +private: + unsigned m_id; + unsigned m_request_uid; + unsigned m_warp_id; + new_addr_type m_addr; // address being fetched + std::vector<inst_t> m_insts; + bool m_iswrite; + bool m_merged_on_other_reqest; //true if waiting for another mshr - this mshr doesn't send a memory request + struct mshr_entry *m_merged_requests; //mshrs waiting on this mshr + enum mshr_status m_status; + class mem_fetch *m_mf; // link to corresponding memory fetch structure + bool m_isinst; //if it's a request from the instruction cache + bool m_istexture; //if it's a request from the texture cache + bool m_isconst; //if it's a request from the constant cache + bool m_islocal; //if it's a request to the local memory of a thread + bool m_wt_no_w2cache; //in write_through, sometimes need to prevent writing back returning data into cache, because its been written in the meantime. }; - -/* A pointer to the function that glues the shader with the memory hiearchy */ -typedef unsigned char (*fq_push_t)(unsigned long long int addr, int bsize, unsigned char readwrite, - partial_write_mask_t, - int sid, int wid, mshr_entry* mshr, int cache_hits_waiting, - enum mem_access_type mem_acc, address_type pc); - -typedef unsigned char (*fq_has_buffer_t)(unsigned long long int addr, int bsize, bool write, int sid); - const unsigned WARP_PER_CTA_MAX = 32; typedef std::bitset<WARP_PER_CTA_MAX> warp_set_t; -inst_t *first_valid_thread( inst_t *warp ); -void move_warp( inst_t *dst, inst_t *src ); -bool pipeline_regster_empty( inst_t *reg ); -std::list<unsigned> get_regs_written( inst_t *warp ); -int register_bank(int regnum, int tid); +int register_bank(int regnum, int tid, unsigned num_banks, unsigned bank_warp_shift); + class shader_core_ctx; -void shader_print_warp( const shader_core_ctx *shader, inst_t *warp, FILE *fout, int stage_width, int print_mem, int mask ) ; -class opndcoll_rfu_t{ // operand collector based register file unit +class opndcoll_rfu_t { // operand collector based register file unit public: // constructors opndcoll_rfu_t() @@ -343,29 +472,28 @@ public: void init( unsigned num_collectors_alu, unsigned num_collectors_sfu, unsigned num_banks, - const shader_core_ctx *shader ); + shader_core_ctx *shader, + inst_t **alu_port, + inst_t **sfu_port ); // modifiers - void writeback( inst_t *warp ) + bool writeback( const inst_t &fvt ); + bool writeback( inst_t *warp ); // might cause stall + + void step( inst_t *&id_oc_reg ) { - // prefer not to stall writeback - inst_t *fvt=first_valid_thread(warp); - if (!fvt) return; - unsigned tid = fvt->hw_thread_id; - std::list<unsigned> regs = get_regs_written(fvt); - std::list<unsigned>::iterator r; - for( r=regs.begin(); r!=regs.end();r++ ) { - unsigned reg = *r; - unsigned bank = register_bank(reg,tid); - m_arbiter.allocate_bank_for_write(bank,op_t(fvt,reg)); - } + dispatch_ready_cu(); + allocate_reads(); + allocate_cu(id_oc_reg); + process_banks(); } - void step( inst_t *id_oc_reg ) + void step( inst_t *&alu_issue_port, inst_t *&sfu_issue_port ) { dispatch_ready_cu(); allocate_reads(); - allocate_cu(id_oc_reg); + allocate_cu(alu_issue_port); + allocate_cu(sfu_issue_port); process_banks(); } @@ -374,12 +502,14 @@ public: fprintf(fp,"\n"); fprintf(fp,"Operand Collector State:\n"); for( unsigned n=0; n < m_num_collectors; n++ ) { - fprintf(fp," CU-%u: ", n); + fprintf(fp," CU-%2u: ", n); m_cu[n].dump(fp,m_shader); } m_arbiter.dump(fp); } + shader_core_ctx *shader_core() { return m_shader; } + private: void process_banks() @@ -387,61 +517,9 @@ private: m_arbiter.reset_alloction(); } - void dispatch_ready_cu() - { - port_to_du_t::iterator p; - for( p=m_dispatch_units.begin(); p!=m_dispatch_units.end(); ++p ) { - inst_t *port = p->first; - if( !pipeline_regster_empty(port) ) - continue; - dispatch_unit_t &du = p->second; - collector_unit_t *cu = du.find_ready(); - if( cu ) { - cu->dispatch(); - m_free_cu[port].push_back(cu); - } - } - } - - void allocate_cu( inst_t *id_oc_reg ) - { - inst_t *fvi = first_valid_thread(id_oc_reg); - if( fvi ) { - inst_t *port = NULL; - if( fvi->op == SFU_OP ) - port = m_sfu_port; - else - port = m_alu_port; - if( !m_free_cu[port].empty() ) { - collector_unit_t *cu = m_free_cu[port].back(); - m_free_cu[port].pop_back(); - cu->allocate(id_oc_reg); - m_arbiter.add_read_requests(cu); - } - } - } - - void allocate_reads() - { - // process read requests that do not have conflicts - std::list<op_t> allocated = m_arbiter.allocate_reads(); - std::map<unsigned,op_t> read_ops; - for( std::list<op_t>::iterator r=allocated.begin(); r!=allocated.end(); r++ ) { - const op_t &rr = *r; - unsigned reg = rr.get_reg(); - unsigned tid = rr.get_tid(); - unsigned bank = register_bank(reg,tid); - m_arbiter.allocate_for_read(bank,rr); - read_ops[bank] = rr; - } - std::map<unsigned,op_t>::iterator r; - for(r=read_ops.begin();r!=read_ops.end();++r ) { - op_t &op = r->second; - unsigned cu = op.get_oc_id(); - unsigned operand = op.get_operand(); - m_cu[cu].collect_operand(operand); - } - } + void dispatch_ready_cu(); + void allocate_cu( inst_t *&id_oc_reg ); + void allocate_reads(); // types @@ -451,7 +529,7 @@ private: public: op_t() { m_valid = false; } - op_t( collector_unit_t *cu, unsigned op, unsigned reg ) + op_t( collector_unit_t *cu, unsigned op, unsigned reg, unsigned num_banks, unsigned bank_warp_shift ) { m_valid = true; m_fvi=NULL; @@ -459,16 +537,17 @@ private: m_operand = op; m_register = reg; m_tid = cu->get_tid(); - m_bank = register_bank(reg,m_tid); + m_bank = register_bank(reg,m_tid,num_banks,bank_warp_shift); } - op_t( inst_t *fvi, unsigned reg ) + op_t( const inst_t *fvi, unsigned reg, unsigned num_banks, unsigned bank_warp_shift ) { + m_valid=true; m_fvi=fvi; m_register=reg; m_cu=NULL; m_operand = -1; m_tid = fvi->hw_thread_id; - m_bank = register_bank(reg,m_tid); + m_bank = register_bank(reg,m_tid,num_banks,bank_warp_shift); } // accessors @@ -487,7 +566,7 @@ private: if(m_cu) fprintf(fp," <R%u, CU:%u, w:%02u> ", m_register,m_cu->get_id(),m_cu->get_warp_id()); else if( m_fvi ) - fprintf(fp," <R%u, w:%02u> ", m_register,m_tid/::warp_size); + fprintf(fp," <R%u, fvi tid:%02u> ", m_register,m_fvi->hw_thread_id ); } std::string get_reg_string() const { @@ -501,7 +580,7 @@ private: private: bool m_valid; collector_unit_t *m_cu; - inst_t *m_fvi; + const inst_t *m_fvi; unsigned m_operand; // operand offset in instruction. e.g., add r1,r2,r3; r2 is oprd 0, r3 is 1 (r1 is dst) unsigned m_register; unsigned m_bank; @@ -591,12 +670,18 @@ private: } } } + bool bank_idle( unsigned bank ) const + { + return m_allocated_bank[bank].is_free(); + } void allocate_bank_for_write( unsigned bank, const op_t &op ) { + assert( bank < m_num_banks ); m_allocated_bank[bank].alloc_write(op); } void allocate_for_read( unsigned bank, const op_t &op ) { + assert( bank < m_num_banks ); m_allocated_bank[bank].alloc_read(op); } void reset_alloction() @@ -622,83 +707,51 @@ private: collector_unit_t() { m_free = true; - m_warp = (inst_t*)calloc(sizeof(inst_t),::warp_size); + m_warp = NULL; m_src_op = new op_t[MAX_REG_OPERANDS]; m_not_ready.reset(); m_tid = -1; m_warp_id = -1; + m_num_banks = 0; + m_bank_warp_shift = 0; } // accessors - bool ready() const - { - return (!m_free) && m_not_ready.none() && pipeline_regster_empty(m_port); - } + bool ready() const; const op_t *get_operands() const { return m_src_op; } - void dump(FILE *fp, const shader_core_ctx *shader ) const - { - if( m_free ) { - fprintf(fp," <free>\n"); - } else { - shader_print_warp(shader,m_warp,fp,::warp_size,0,0); - for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) { - if( m_not_ready.test(i) ) { - std::string r = m_src_op[i].get_reg_string(); - fprintf(fp," '%s' not ready\n", r.c_str() ); - } - } - } - } + void dump(FILE *fp, const shader_core_ctx *shader ) const; unsigned get_tid() const { return m_tid; } // returns hw id of first valid instruction unsigned get_warp_id() const { return m_warp_id; } unsigned get_id() const { return m_cuid; } // returns CU hw id // modifiers - void init(unsigned n, inst_t *port) { m_cuid=n; m_port=port; } - void allocate( inst_t *pipeline_reg ) - { - assert(m_free); - assert(m_not_ready.none()); - m_free = false; - inst_t *fvi = first_valid_thread(pipeline_reg); - if( fvi ) { - m_tid = fvi->hw_thread_id; - m_warp_id = m_tid/::warp_size; - for( unsigned op=0; op < 4; op++ ) { - int reg_num = fvi->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst - if( reg_num >= 0 ) { // valid register - m_src_op[op] = op_t( this, op, reg_num ); - m_not_ready.set(op); - } else - m_src_op[op] = op_t(); - } - move_warp(m_warp,pipeline_reg); - } - } + void init(unsigned n, + inst_t **port, + unsigned num_banks, + unsigned log2_warp_size, + unsigned warp_size, + opndcoll_rfu_t *rfu ); + void allocate( inst_t *&pipeline_reg ); void collect_operand( unsigned op ) { m_not_ready.reset(op); } - void dispatch() - { - assert( m_not_ready.none() ); - move_warp(m_port,m_warp); - m_free=true; - for( unsigned i=0; i<MAX_REG_OPERANDS;i++) - m_src_op[i].reset(); - } + void dispatch(); private: bool m_free; unsigned m_tid; unsigned m_cuid; // collector unit hw id - inst_t *m_port; // pipeline register to issue to when ready + inst_t **m_port; // pipeline register to issue to when ready unsigned m_warp_id; inst_t *m_warp; op_t *m_src_op; std::bitset<MAX_REG_OPERANDS> m_not_ready; + unsigned m_num_banks; + unsigned m_bank_warp_shift; + opndcoll_rfu_t *m_rfu; }; class dispatch_unit_t { @@ -748,16 +801,18 @@ private: unsigned m_num_collectors; unsigned m_num_banks; + unsigned m_bank_warp_shift; + unsigned m_warp_size; collector_unit_t *m_cu; arbiter_t m_arbiter; - inst_t *m_alu_port; - inst_t *m_sfu_port; + inst_t **m_alu_port; + inst_t **m_sfu_port; - typedef std::map<inst_t*/*port*/,dispatch_unit_t> port_to_du_t; + typedef std::map<inst_t**/*port*/,dispatch_unit_t> port_to_du_t; port_to_du_t m_dispatch_units; - std::map<inst_t*,std::list<collector_unit_t*> > m_free_cu; - const shader_core_ctx *m_shader; + std::map<inst_t**,std::list<collector_unit_t*> > m_free_cu; + shader_core_ctx *m_shader; }; class barrier_set_t { @@ -782,7 +837,7 @@ public: void warp_exit( unsigned warp_id ); // assertions - bool warp_waiting_at_barrier( unsigned warp_id ); + bool warp_waiting_at_barrier( unsigned warp_id ) const; // debug void dump() const; @@ -796,213 +851,431 @@ private: warp_set_t m_warp_at_barrier; }; -class mshr_shader_unit; class warp_tracker; class warp_tracker_pool; +enum memory_pipe_t { + NO_MEM_PATH = 0, + SHARED_MEM_PATH, + GLOBAL_MEM_PATH, + TEXTURE_MEM_PATH, + CONSTANT_MEM_PATH, + NUM_MEM_PATHS //not a mem path +}; + +class mem_access_t { +public: + mem_access_t() : space(undefined_space) + { + init(); + } + mem_access_t(address_type a, memory_space_t s, memory_pipe_t p, bool atomic, bool w, unsigned r, unsigned quarter, unsigned idx ) + { + init(); + addr = a; + space = s; + mem_pipe = p; + isatomic = atomic; + iswrite = w; + req_size = r; + quarter_count[quarter]++; + warp_indices.push_back(idx); + } + + bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse + +private: + void init() + { + uid=++next_access_uid; + addr=0; + req_size=0; + order=0; + _quarter_count_all=0; + mem_pipe = NO_MEM_PATH; + isatomic = false; + cache_hit = false; + cache_checked = false; + recheck_cache = false; + iswrite = false; + need_wb = false; + wb_addr = 0; + reserved_mshr = NULL; + } + +public: + + unsigned uid; + address_type addr; //address of the segment to load. + unsigned req_size; //bytes + unsigned order; // order of accesses, based on banks. + union{ + unsigned _quarter_count_all; + char quarter_count[4]; //access counts to each quarter of segment, for compaction; + }; + std::vector<unsigned> warp_indices; // warp indicies for this request. + memory_space_t space; + memory_pipe_t mem_pipe; + bool isatomic; + bool cache_hit; + bool cache_checked; + bool recheck_cache; + bool iswrite; + bool need_wb; + address_type wb_addr; // writeback address (if necessary). + mshr_entry* reserved_mshr; + +private: + static unsigned next_access_uid; +}; + +class mshr_lookup { +public: + mshr_lookup( const struct shader_core_config *config ) { m_shader_config = config; } + bool can_merge(mshr_entry * mshr); + void mshr_fast_lookup_insert(mshr_entry* mshr); + void mshr_fast_lookup_remove(mshr_entry* mshr); + mshr_entry* shader_get_mergeable_mshr(mshr_entry* mshr); + +private: + void insert(mshr_entry* mshr); + mshr_entry* lookup(new_addr_type addr) const; + void remove(mshr_entry* mshr); + + typedef std::multimap<new_addr_type, mshr_entry*> mshr_lut_t; // multimap since multiple mshr entries can have the same tag + + const shader_core_config *m_shader_config; + mshr_lut_t m_lut; +}; + +class mshr_shader_unit { +public: + mshr_shader_unit( const shader_core_config *config ); + + bool has_mshr(unsigned num) + { + return (num <= m_free_list.size()); + } + + //return queue access; (includes texture pipeline return) + mshr_entry* return_head(); + + //return queue pop; (includes texture pipeline return) + void pop_return_head(); + + mshr_entry* add_mshr(mem_access_t &access, inst_t* warp); + void mshr_return_from_mem(mshr_entry *mshr); + unsigned get_max_mshr_used() const {return m_max_mshr_used;} + void print(FILE* fp, class shader_core_ctx* shader,unsigned mask); + +private: + mshr_entry *alloc_free_mshr(bool istexture); + void free_mshr( mshr_entry *mshr ); + unsigned mshr_used() const; + bool has_return() + { + return (not m_mshr_return_queue.empty()) or + ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched()); + } + std::deque<mshr_entry*> &choose_return_queue(); + + const struct shader_core_config *m_shader_config; + + typedef std::vector<mshr_entry> mshr_storage_type; + mshr_storage_type m_mshrs; + std::deque<mshr_entry*> m_free_list; + std::deque<mshr_entry*> m_mshr_return_queue; + std::deque<mshr_entry*> m_texture_mshr_pipeline; + unsigned m_max_mshr_used; + mshr_lookup m_mshr_lookup; +}; + +struct shader_queues_t { + std::vector<mem_access_t> shared; + std::vector<mem_access_t> constant; + std::vector<mem_access_t> texture; + std::vector<mem_access_t> local_global; +}; + +struct insn_latency_info { + unsigned pc; + unsigned long latency; +}; + +struct ifetch_buffer_t { + ifetch_buffer_t() { m_valid=false; } + + ifetch_buffer_t( address_type pc, unsigned nbytes, unsigned warp_id ) + { + m_valid=true; + m_pc=pc; + m_nbytes=nbytes; + m_warp_id=warp_id; + } + + bool m_valid; + address_type m_pc; + unsigned m_nbytes; + unsigned m_warp_id; +}; + +// Struct for storing warp information in fixeddelay_queue +struct fixeddelay_queue_warp_t { + unsigned long long ready_cycle; + std::vector<int> tids; // list of tid's in this warp (to unlock) + inst_t inst; +}; + +struct fixeddelay_queue_warp_comp { + inline bool operator()(const fixeddelay_queue_warp_t& left,const fixeddelay_queue_warp_t& right) const + { + return left.ready_cycle < right.ready_cycle; + } +}; + +typedef address_type (*tag_func_t)(address_type add, unsigned line_size); + class shader_core_ctx : public core_t { public: - shader_core_ctx( const char *name, int sid, - unsigned int n_threads, - unsigned int n_mshr, - fq_push_t fq_push, - fq_has_buffer_t fq_has_buffer, - unsigned model, - unsigned max_warps_per_cta, unsigned max_cta_per_core ); + shader_core_ctx( class gpgpu_sim *gpu, + const char *name, + unsigned shader_id, + unsigned tpc_id, + const struct shader_core_config *config, + struct shader_core_stats *stats ); + + void issue_block2core( class kernel_info_t &kernel ); + void get_pdom_stack_top_info( unsigned tid, unsigned *pc, unsigned *rpc ); + void new_cache_window(); + bool ptx_thread_done( unsigned hw_thread_id ) const; + class ptx_thread_info *get_thread_state( unsigned hw_thread_id ); - virtual void set_at_barrier( unsigned cta_id, unsigned warp_id ); + virtual void set_at_barrier( unsigned cta_id, unsigned warp_id ); virtual void warp_exit( unsigned warp_id ); - virtual bool warp_waiting_at_barrier( unsigned warp_id ); + virtual bool warp_waiting_at_barrier( unsigned warp_id ) const; + virtual bool warp_waiting_for_atomics( unsigned warp_id ) const; + virtual class gpgpu_sim *get_gpu(); + void set_at_memory_barrier( unsigned warp_id ); + bool warp_waiting_at_mem_barrier( unsigned warp_id ); void allocate_barrier( unsigned cta_id, warp_set_t warps ); void deallocate_barrier( unsigned cta_id ); + void decrement_atomic_count( unsigned wid ); -//// - - const char *name; - int sid; + void cycle(); + void cycle_gt200(); - // array of the threads running on this shader core - thread_ctx_t *thread; - unsigned int n_threads; - unsigned int last_issued_thread; + void reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed ); + void init_warps(unsigned start_thread, unsigned end_thread); - //per warp information array - std::vector<shd_warp_t> warp; + unsigned max_cta( class function_info *kernel ); + void cache_flush(); + void display_pdom_state(FILE *fout, int mask ); + void display_pipeline( FILE *fout, int print_mem, int mask3bit ); + void register_cta_thread_exit(int cta_num ); + void fill_shd_L1_with_new_line( class mem_fetch * mf ); + void store_ack( class mem_fetch *mf ); + void dump_istream_state( FILE *fout ); + void mshr_print(FILE* fp, unsigned mask); + inst_t *first_valid_thread( inst_t *warp ); + inst_t *first_valid_thread( unsigned stage ); + class ptx_thread_info* get_functional_thread( unsigned tid ) { return m_thread[tid].m_functional_model_thread_state; } + void move_warp( inst_t *&dst, inst_t *&src ); + void print_warp( inst_t *warp, FILE *fout, int print_mem, int mask ) const; + void clear_stage(inst_t *warp); + std::list<unsigned> get_regs_written( const inst_t &fvt ) const; + bool pipeline_regster_empty( inst_t *reg ); + const shader_core_config *get_config() const { return m_config; } + unsigned get_num_sim_insn() const { return m_num_sim_insn; } + int get_not_completed() const { return m_not_completed; } + unsigned get_n_diverge() const { return m_n_diverge; } + unsigned get_thread_n_insn( unsigned tid ) const { return m_thread[tid].n_insn; } + unsigned get_thread_n_insn_ac( unsigned tid ) const { return m_thread[tid].n_insn_ac; } + unsigned get_thread_n_l1_mis_ac( unsigned tid ) const { return m_thread[tid].n_l1_mis_ac; } + unsigned get_thread_n_l1_mrghit_ac( unsigned tid ) const { return m_thread[tid].n_l1_mrghit_ac; } + unsigned get_thread_n_l1_access_ac( unsigned tid ) const { return m_thread[tid].n_l1_access_ac; } + unsigned get_max_mshr_used() const { return m_mshr_unit->get_max_mshr_used(); } + void L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const; + void L1texcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const; + void L1constcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const; + unsigned get_n_active_cta() const { return m_n_active_cta; } + float L1_windowed_cache_miss_rate( int x ) const { return shd_cache_windowed_cache_miss_rate(m_L1D,x); } + float L1tex_windowed_cache_miss_rate( int x ) const { return shd_cache_windowed_cache_miss_rate(m_L1T,x); } + float L1const_windowed_cache_miss_rate( int x ) const { return shd_cache_windowed_cache_miss_rate(m_L1C,x); } + +private: - barrier_set_t m_barriers; + void clear_stage_reg(int stage); - //Keeps track of which warp of instructions to fetch/execute - int next_warp; + address_type next_pc( int tid ) const; - // number of threads to be completed ( ==0 when all thread on this core completed) - int not_completed; - // number of Cuda Thread Arrays (blocks) currently running on this shader. - int n_active_cta; - //Keep track of multiple CTAs in shader - int cta_status[MAX_CTA_PER_SHADER]; - // registers holding the instruction between pipeline stages. - // see below for definition of pipeline stages - inst_t** pipeline_reg; - inst_t** pre_mem_pipeline; - opndcoll_rfu_t m_opndcoll_new; - int warp_part2issue; // which part of warp to issue to pipeline - int new_warp_TS; // new warp at TS pipeline register + void ptx_exec_inst( inst_t &inst ); + void fetch_new(); + void issue_warp(const inst_t *pI, unsigned active_mask, inst_t *&warp, unsigned warp_id ); + void decode_new(); - shd_cache_t *L1cache; - shd_cache_t *L1texcache; - shd_cache_t *L1constcache; + void fetch(); - // pointer to memory access wrapping function - fq_push_t fq_push; - fq_has_buffer_t fq_has_buffer; + void fetch_mimd(); + void fetch_simd_dwf(); + void fetch_simd_postdominator(); + int pdom_sched_find_next_warp (int ready_warp_count); + bool fetch_stalled(); + void shader_issue_thread(int tid, int wlane, unsigned active_mask ); + int warp_reached_barrier(int *tid_in); - // simulation cycles happened to the shader, kept for cacheline replacement - unsigned int gpu_cycle; - // number of instructions committed by this shader core - unsigned int num_sim_insn; + void decode(); - // reconvergence - unsigned int model; + void preexecute(); - // Structure is used to keep track of the branching within the warp of instructions. - // As a group of instructions is grouped together from different threads to be executed, when - // a branch does occur, then the sub-set that does not get run will be given the value of warp_priority, - // and warp_priority will increase. Each time a sub-set branches further, a similar scheme is used. - // When a sub-set completes fully, then this table will determine which next sub-set to finish, which - // will be the next largest value in the table. - int branch_priority; - int* max_branch_priority; //Keeps track of the maximum priority of the threads running within a warp. need n_threads number of these + void execute(); + void execute_pipe( unsigned pipeline, unsigned next_stage ); - // pdom reconvergence context for each warp - pdom_warp_ctx_t *pdom_warp; + void pre_memory(); - int waiting_at_barrier; // number of threads current waiting at a barrier in this shader. - int RR_k; //counter for register read pipeline + void memory(); // advance memory pipeline stage + void memory_queue(); + void memory_shared_process_warp(); + void memory_const_process_warp(); + void memory_texture_process_warp(); + void memory_global_process_warp(); + bool memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + bool memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + bool memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + bool memory_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + address_type translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader ); - int using_dwf; //is the scheduler using dynamic warp formation - int using_rrstage; //is the pipeline using an extra stage for register read - int using_commit_queue; //is the scheduler using commit_queue? + mem_stage_stall_type ccache_check(mem_access_t& access){ return NO_RC_FAIL;} + mem_stage_stall_type tcache_check(mem_access_t& access){ return NO_RC_FAIL;} + mem_stage_stall_type dcache_check(mem_access_t& access); - delay_queue *thd_commit_queue; + typedef mem_stage_stall_type (shader_core_ctx::*cache_check_t)(mem_access_t&); - int pending_shmem_bkacc; // 0 = check conflict for new insn - int pending_cache_bkacc; // 0 = check conflict for new insn + mem_stage_stall_type process_memory_access_queue( shader_core_ctx::cache_check_t cache_check, + unsigned ports_per_bank, + unsigned memory_send_max, + std::vector<mem_access_t> &accessq ); - bool shader_memory_new_instruction_processed; + typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size); + + int null_bank_func(address_type add, unsigned line_size); + int shmem_bank_func(address_type add, unsigned line_size); + int dcache_bank_func(address_type add, unsigned line_size); - int pending_mem_access; // number of memory access to be serviced (use for W0 classification) + void get_memory_access_list( bank_func_t bank_func, + tag_func_t tag_func, + memory_pipe_t mem_pipe, + unsigned warp_parts, + unsigned line_size, + bool limit_broadcast, + std::vector<mem_access_t> &accessq ); + mem_stage_stall_type send_mem_request(mem_access_t &access); - int pending_cmem_acc; //number of accesses to differrnt addresses in the constant memory cache + void check_stage_pcs( unsigned stage ); + void check_pm_stage_pcs( unsigned stage ); - unsigned int n_diverge; // number of divergence occurred in this shader + void writeback(); + int split_warp_by_pc(int *tid_in, int **tid_split, address_type *pc); + int split_warp_by_cta(int *tid_in, int **tid_split, address_type *pc, int *cta); - //Shader core resources - unsigned int shmem_size; - unsigned int n_registers; //registers available in the shader core - unsigned int n_cta; //Limit on number of concurrent CTAs in shader core + unsigned char fq_push( unsigned long long int addr, + int bsize, + unsigned char write, + partial_write_mask_t partial_write_mask, + int wid, mshr_entry* mshr, + int cache_hits_waiting, + enum mem_access_type mem_acc, + address_type pc ); - mshr_shader_unit *mshr_unit; + bool warp_scoreboard_hazard(int warp_id); + mshr_entry* check_mshr4tag(unsigned long long int addr,int mem_type); + void update_mshr(unsigned long long int fetched_addr, unsigned int mshr_idx, int mem_type ); + void visualizer_dump(FILE *fp); + void clean(unsigned int n_threads); + void call_thread_done(inst_t &done_inst ); + void queue_warp_unlocking(int *tids, const inst_t &inst ); + void process_delay_queue(); + void unlock_warp(std::vector<int> tids ); - // - // Fixed-delay queue for locked warps - // + void print_pre_mem_stages( FILE *fout, int print_mem, int mask ); + void print_stage(unsigned int stage, FILE *fout, int print_mem, int mask ); + void print_shader_cycle_distro( FILE *fout ); - // Struct for storing warp information in fixeddelay_queue - struct fixeddelay_queue_warp_t { - int grid_num; - unsigned long long ready_cycle; - std::vector<int> tids; // list of tid's in this warp (to unlock) - }; - struct fixeddelay_queue_warp_comp { - inline bool operator()(const fixeddelay_queue_warp_t& left,const fixeddelay_queue_warp_t& right) const - { - return left.ready_cycle < right.ready_cycle; - } - }; + // general information + unsigned m_sid; // shader id + unsigned m_tpc; // texture processor cluster id (aka, node id when using interconnect concentration) + const char *m_name; + const shader_core_config *m_config; + class gpgpu_sim *m_gpu; - // The queue - std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp> fixeddelay_queue; + // statistics + struct shader_core_stats *m_stats; // pointer to single object shared by all shader cores in GPU + unsigned int m_num_sim_insn; // number of instructions committed by this shader core + unsigned int m_n_diverge; // number of divergence occurred in this shader - // Scoreboard - Scoreboard *scrb; -}; + // CTA scheduling / hardware thread allocation + int m_n_active_cta; // number of Cooperative Thread Arrays (blocks) currently running on this shader. + int m_cta_status[MAX_CTA_PER_SHADER]; // CTAs status + int m_not_completed; // number of threads to be completed (==0 when all thread on this core completed) -typedef shader_core_ctx shader_core_ctx_t; + // thread contexts + thread_ctx_t *m_thread; // functional state, per thread fetch state + std::vector<shd_warp_t> m_warp; // per warp information array + barrier_set_t m_barriers; + ifetch_buffer_t m_inst_fetch_buffer; + pdom_warp_ctx_t **m_pdom_warp; // pdom reconvergence context for each warp -typedef struct { - unsigned pc; - unsigned long latency; - void *ptx_thd_info; -} insn_latency_info; + class warp_tracker_pool *m_warp_tracker; + inst_t** m_pipeline_reg; + inst_t** pre_mem_pipeline; + Scoreboard *m_scoreboard; + opndcoll_rfu_t m_operand_collector; + mshr_shader_unit *m_mshr_unit; + shader_queues_t m_memory_queue; + fifo_pipeline<std::vector<int> > *m_thd_commit_queue; + std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp> m_fixeddelay_queue; + // fetch + int m_last_warp_fetched; + int m_last_warp_issued; -shader_core_ctx_t* shader_create( const char *name, int sid, unsigned int n_threads, - unsigned int n_mshr, fq_push_t fq_push, fq_has_buffer_t fq_has_buffer, unsigned int model); -unsigned shader_reinit(shader_core_ctx_t *sc, int start_thread, int end_thread); -void shader_init_CTA(shader_core_ctx_t *shader, int start_thread, int end_thread); + bool m_new_warp_TS; // new warp at TS pipeline register + int m_last_warp; // SIMT: last warp issued + int m_next_warp; // SIMT: Keeps track of which warp of instructions to fetch/execute + unsigned m_last_issued_thread; // MIMD -void shader_fetch( shader_core_ctx_t *shader, - unsigned int shader_number, - int grid_num ); -void shader_decode( shader_core_ctx_t *shader, - unsigned int shader_number, - unsigned int grid_num ); -void shader_preexecute( shader_core_ctx_t *shader, - unsigned int shader_number ); -void shader_execute( shader_core_ctx_t *shader, - unsigned int shader_number ); -void shader_pre_memory( shader_core_ctx_t *shader, - unsigned int shader_number ); -void shader_const_memory( shader_core_ctx_t *shader, - unsigned int shader_number ); -void shader_texture_memory( shader_core_ctx_t *shader, - unsigned int shader_number ); -void shader_memory( shader_core_ctx_t *shader, - unsigned int shader_number ); -void shader_writeback( shader_core_ctx_t *shader, - unsigned int shader_number, - int grid_num ); + int *m_ready_warps; + int *m_tmp_ready_warps; + int *m_fetch_tid_out; -bool shader_warp_scoreboard_hazard(shader_core_ctx_t *shader, int warp_id); -void shader_pdom_update_warp_mask(shader_core_ctx_t *shader, int warp_id); + // pre-execute stage + int m_dwf_RR_k; // counter for register read pipeline + int *m_dwf_rrstage_bank_access_counter; -void shader_display_pipeline(shader_core_ctx_t *shader, FILE *fout, int print_mem, int mask3bit ); -void shader_dump_thread_state(shader_core_ctx_t *shader, FILE *fout ); -void shader_cycle( shader_core_ctx_t *shader, - unsigned int shader_number, - int grid_num ); + shd_cache_t *m_L1I; // instruction cache + shd_cache_t *m_L1D; // data cache (global/local memory accesses) + shd_cache_t *m_L1T; // texture cache + shd_cache_t *m_L1C; // constant cache -void mshr_print(FILE *fp, shader_core_ctx_t *shader); + bool m_shader_memory_new_instruction_processed; + int m_pending_mem_access; // number of memory access to be serviced (use for W0 classification) -void mshr_update_status(mshr_entry* mshr, enum mshr_status new_status); + // used in writeback + int *m_pl_tid; + insn_latency_info *m_mshr_lat_info; + insn_latency_info *m_pl_lat_info; -mshr_entry* fetchMSHR(delay_queue** mshr, shader_core_ctx_t* sc); -mshr_entry* shader_check_mshr4tag(shader_core_ctx_t* sc, unsigned long long int addr,int mem_type); -void shader_update_mshr(shader_core_ctx_t* sc, unsigned long long int fetched_addr, unsigned int mshr_idx, int mem_type ); -void shader_visualizer_dump(FILE *fp, shader_core_ctx_t* sc); + class thread_pc_tracker *m_thread_pc_tracker; +}; void init_mshr_pool(); mshr_entry* alloc_mshr_entry(); void free_mshr_entry( mshr_entry * ); -void shader_clean(shader_core_ctx_t *sc, unsigned int n_threads); -void shader_cache_flush(shader_core_ctx_t* sc); - -void shader_call_thread_done( shader_core_ctx_t *shader, int grid_num, inst_t &done_inst ); -void shader_queue_warp_unlocking(shader_core_ctx_t *shader, int *tids, memory_space_t space, int grid_num); -void shader_process_delay_queue(shader_core_ctx_t *shader); -void shader_unlock_warp(shader_core_ctx_t *shd, std::vector<int> tids, int grid_num); - // print out the accumulative statistics for shaders (those that are not local to one shader) -void shader_print_accstats( FILE* fout ); void shader_print_runtime_stat( FILE *fout ); void shader_print_l1_miss_stat( FILE *fout ); -//return the maximum CTAs that can be running at the same on shader -//based on on the current kernel's CTA size and is 1 if mutiple CTA per block is not supported -unsigned int max_cta_per_shader( shader_core_ctx_t *shader); - #define TS_IF 0 #define IF_ID 1 #define ID_RR 2 @@ -1011,45 +1284,14 @@ unsigned int max_cta_per_shader( shader_core_ctx_t *shader); #define EX_MM 4 #define MM_WB 5 #define WB_RT 6 - #define ID_OC 7 -#define OC_EX_SFU 8 +#define ID_OC_SFU 8 +#define OC_EX_SFU 9 +#define N_PIPELINE_STAGES 10 -#define N_PIPELINE_STAGES 9 - -extern shader_core_ctx_t **sc; -extern unsigned int gpgpu_n_load_insn; -extern unsigned int gpgpu_n_store_insn; -extern unsigned int gpgpu_n_shmem_insn; -extern unsigned int gpgpu_n_tex_insn; -extern unsigned int gpgpu_n_const_insn; -extern unsigned int gpgpu_multi_unq_fetches; -extern unsigned int gpgpu_n_cache_bkconflict; -extern unsigned int gpgpu_n_shmem_bkconflict; -extern int gpgpu_warpdistro_shader; extern unsigned int *shader_cycle_distro; -extern int gpgpu_interwarp_mshr_merge; -extern unsigned int gpgpu_shmem_size; -extern unsigned int gpgpu_shader_registers; -extern unsigned int gpgpu_shader_cta; -extern bool gpgpu_shmem_bkconflict; -extern bool gpgpu_cache_bkconflict; -extern int gpgpu_n_cache_bank; -extern int pipe_simd_width; -extern int gpgpu_shmem_port_per_bank; -extern int gpgpu_cache_port_per_bank; -extern int gpgpu_const_port_per_bank; -extern int gpgpu_shmem_pipe_speedup; -extern bool gpgpu_reg_bank_conflict_model; -extern unsigned int gpgpu_num_reg_banks; -extern bool gpgpu_reg_bank_use_warp_id; -extern unsigned int gpu_max_cta_per_shader; -extern unsigned int gpu_padded_cta_size; -extern int gpgpu_local_mem_map; extern unsigned int n_regconflict_stall; -extern int gpgpu_coalesce_arch; -extern unsigned get_max_mshr_used(shader_core_ctx_t* shader); -extern void mshr_return_from_mem(shader_core_ctx_t * shader, mshr_entry_t* mshr); -void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc ); + +int is_store ( const inst_t &op ); #endif /* SHADER_H */ diff --git a/src/gpgpu-sim/stat-tool.cc b/src/gpgpu-sim/stat-tool.cc index c136d57..af43b72 100644 --- a/src/gpgpu-sim/stat-tool.cc +++ b/src/gpgpu-sim/stat-tool.cc @@ -985,12 +985,13 @@ static int s_cache_access_logger_n_types = 0; static std::vector<linear_histogram_logger> s_cache_access_logger; enum cache_access_logger_types { - NORMAL, TEXTURE, CONSTANT + NORMAL, TEXTURE, CONSTANT, INSTRUCTION }; int get_shader_normal_cache_id() { return NORMAL; } int get_shader_texture_cache_id() { return TEXTURE; } int get_shader_constant_cache_id() { return CONSTANT; } +int get_shader_instruction_cache_id() { return INSTRUCTION; } void shader_cache_access_create( int n_loggers, int n_types, unsigned long long logging_interval) { @@ -1010,7 +1011,7 @@ void shader_cache_access_log( int logger_id, int type, int miss) { if (s_cache_access_logger_n_types == 0) return; if (logger_id < 0) return; - assert(type == NORMAL || type == TEXTURE || type == CONSTANT); + assert(type == NORMAL || type == TEXTURE || type == CONSTANT || type == INSTRUCTION); assert(miss == 0 || miss == 1); s_cache_access_logger[logger_id].log(2 * type + miss); @@ -1020,7 +1021,7 @@ void shader_cache_access_unlog( int logger_id, int type, int miss) { if (s_cache_access_logger_n_types == 0) return; if (logger_id < 0) return; - assert(type == NORMAL || type == TEXTURE || type == CONSTANT); + assert(type == NORMAL || type == TEXTURE || type == CONSTANT || type == INSTRUCTION); assert(miss == 0 || miss == 1); s_cache_access_logger[logger_id].unlog(2 * type + miss); diff --git a/src/gpgpu-sim/stat-tool.h b/src/gpgpu-sim/stat-tool.h index d67daf5..3ebe750 100644 --- a/src/gpgpu-sim/stat-tool.h +++ b/src/gpgpu-sim/stat-tool.h @@ -109,6 +109,7 @@ void shader_mem_lat_print( FILE *fout ); int get_shader_normal_cache_id(); int get_shader_texture_cache_id(); int get_shader_constant_cache_id(); +int get_shader_instruction_cache_id(); void shader_cache_access_create( int n_loggers, int n_types, unsigned long long logging_interval ); void shader_cache_access_log( int logger_id, int type, int miss); void shader_cache_access_unlog( int logger_id, int type, int miss); diff --git a/src/gpgpu-sim/stats.h b/src/gpgpu-sim/stats.h new file mode 100644 index 0000000..76e6699 --- /dev/null +++ b/src/gpgpu-sim/stats.h @@ -0,0 +1,138 @@ +/* + * shader.h + * + * Copyright (c) 2009 by Tor M. Aamodt and the + * University of British Columbia + * Vancouver, BC V6T 1Z4 + * All Rights Reserved. + * + * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE + * TERMS AND CONDITIONS. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h + * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda + * (property of NVIDIA). The files benchmarks/BlackScholes/ and + * benchmarks/template/ are derived from the CUDA SDK available from + * http://www.nvidia.com/cuda (also property of NVIDIA). The files from + * src/intersim/ are derived from Booksim (a simulator provided with the + * textbook "Principles and Practices of Interconnection Networks" available + * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by + * the corresponding legal terms and conditions set forth separately (original + * copyright notices are left in files from these sources and where we have + * modified a file our copyright notice appears before the original copyright + * notice). + * + * Using this version of GPGPU-Sim requires a complete installation of CUDA + * which is distributed seperately by NVIDIA under separate terms and + * conditions. To use this version of GPGPU-Sim with OpenCL requires a + * recent version of NVIDIA's drivers which support OpenCL. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the University of British Columbia nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. + * + * 5. No nonprofit user may place any restrictions on the use of this software, + * including as modified by the user, by any other authorized user. + * + * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, + * Ali Bakhoda, George L. Yuan, at the University of British Columbia, + * Vancouver, BC V6T 1Z4 + */ + +#ifndef STATS_INCLUDED +#define STATS_INCLUDED + + + +enum mem_stage_access_type { + C_MEM, + T_MEM, + S_MEM, + G_MEM_LD, + L_MEM_LD, + G_MEM_ST, + L_MEM_ST, + N_MEM_STAGE_ACCESS_TYPE +}; + +enum mem_stage_stall_type { + NO_RC_FAIL = 0, + BK_CONF, + MSHR_RC_FAIL, + ICNT_RC_FAIL, + COAL_STALL, + WB_ICNT_RC_FAIL, + WB_CACHE_RSRV_FAIL, + N_MEM_STAGE_STALL_TYPE +}; + +struct shader_core_stats +{ + unsigned int gpgpu_n_load_insn; + unsigned int gpgpu_n_store_insn; + unsigned int gpgpu_n_shmem_insn; + unsigned int gpgpu_n_tex_insn; + unsigned int gpgpu_n_const_insn; + unsigned int gpgpu_n_param_insn; + unsigned int gpgpu_n_shmem_bkconflict; + unsigned int gpgpu_n_cache_bkconflict; + int gpgpu_n_intrawarp_mshr_merge; + unsigned int gpgpu_n_cmem_portconflict; + int gpgpu_n_partial_writes; + unsigned int gpu_stall_shd_mem_breakdown[N_MEM_STAGE_ACCESS_TYPE][N_MEM_STAGE_STALL_TYPE]; + unsigned int gpu_reg_bank_conflict_stalls; + unsigned int *shader_cycle_distro; + unsigned int L1_write_miss; + unsigned int L1_read_miss; + unsigned int L1_texture_miss; + unsigned int L1_const_miss; + unsigned int L1_write_hit_on_miss; + unsigned int L1_writeback; + int *num_warps_issuable; + int *num_warps_issuable_pershader; + unsigned long long gpu_sim_insn_no_ld_const; + unsigned long long gpu_completed_thread; + unsigned int gpgpu_commit_pc_beyond_two; + unsigned int gpu_stall_by_MSHRwb; + unsigned int gpu_stall_shd_mem; + unsigned int gpu_stall_sh2icnt; + unsigned int *max_return_queue_length; + + //memory access classification + int gpgpu_n_mem_read_local; + int gpgpu_n_mem_write_local; + int gpgpu_n_mem_texture; + int gpgpu_n_mem_const; + int gpgpu_n_mem_read_global; + int gpgpu_n_mem_write_global; + int gpgpu_n_mem_read_inst; + + int n_pdom_sc_orig_stat; + int n_pdom_sc_single_stat; +}; + +#endif diff --git a/src/gpgpu-sim/visualizer.cc b/src/gpgpu-sim/visualizer.cc index 69c4452..fd0a422 100644 --- a/src/gpgpu-sim/visualizer.cc +++ b/src/gpgpu-sim/visualizer.cc @@ -73,7 +73,6 @@ #include <string.h> #include <zlib.h> -static void time_vector_print_interval2file(FILE *outfile); static void time_vector_print_interval2gzfile(gzFile outfile); bool g_visualizer_enabled; @@ -96,13 +95,11 @@ void visualizer_options(option_parser_t opp) } -void visualizer_printstat() +void gpgpu_sim::visualizer_printstat() { gzFile visualizer_file = NULL; // gzFile is basically a pointer to a struct, so it is fine to initialize it as NULL - unsigned i; if ( !g_visualizer_enabled ) return; - // initialize file name if it is not set if ( g_visualizer_filename == NULL ) { time_t curr_time; @@ -131,16 +128,14 @@ void visualizer_printstat() // instruction count per shader core gzprintf(visualizer_file, "shaderinsncount: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%u ",sc[i]->num_sim_insn); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%u ",m_sc[i]->get_num_sim_insn()); gzprintf(visualizer_file, "\n"); // warp divergence per shader core gzprintf(visualizer_file, "shaderwarpdiv: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%u ", sc[i]->n_diverge); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%u ", m_sc[i]->get_n_diverge()); gzprintf(visualizer_file, "\n"); cflog_visualizer_gzprint(visualizer_file); @@ -148,139 +143,82 @@ void visualizer_printstat() // per shader core cache miss rate gzprintf(visualizer_file, "CacheMissRate_GlobalLocalL1_All: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1cache, 0)); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1_windowed_cache_miss_rate(0)); gzprintf(visualizer_file, "\n"); - gzprintf(visualizer_file, "CacheMissRate_TextureL1_All: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1texcache, 0)); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1tex_windowed_cache_miss_rate(0)); gzprintf(visualizer_file, "\n"); - gzprintf(visualizer_file, "CacheMissRate_ConstL1_All: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1constcache, 0)); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1const_windowed_cache_miss_rate(0)); gzprintf(visualizer_file, "\n"); - gzprintf(visualizer_file, "CacheMissRate_GlobalLocalL1_noMgHt: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1cache, 1)); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1_windowed_cache_miss_rate(1)); gzprintf(visualizer_file, "\n"); - gzprintf(visualizer_file, "CacheMissRate_TextureL1_noMgHt: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1texcache, 1)); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1tex_windowed_cache_miss_rate(1)); gzprintf(visualizer_file, "\n"); - gzprintf(visualizer_file, "CacheMissRate_ConstL1_noMgHt: "); - for (i=0;i<gpu_n_shader;i++) { - gzprintf(visualizer_file, "%0.4f ", shd_cache_windowed_cache_miss_rate(sc[i]->L1constcache, 1)); - } + for (unsigned i=0;i<m_n_shader;i++) + gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1const_windowed_cache_miss_rate(1)); gzprintf(visualizer_file, "\n"); // reset for next interval - for (i=0;i<gpu_n_shader;i++) { - shd_cache_new_window(sc[i]->L1cache); - shd_cache_new_window(sc[i]->L1texcache); - shd_cache_new_window(sc[i]->L1constcache); - } - - // dram specific statistics - for (i=0;i<gpu_n_mem;i++) { - gzprintf(visualizer_file, "dramncmd: %u %u\n",dram[i]->id, dram[i]->n_cmd_partial); - gzprintf(visualizer_file, "dramnop: %u %u\n",dram[i]->id,dram[i]->n_nop_partial); - gzprintf(visualizer_file,"dramnact: %u %u\n",dram[i]->id,dram[i]->n_act_partial); - gzprintf(visualizer_file,"dramnpre: %u %u\n",dram[i]->id,dram[i]->n_pre_partial); - gzprintf(visualizer_file,"dramnreq: %u %u\n",dram[i]->id,dram[i]->n_req_partial); - gzprintf(visualizer_file,"dramavemrqs: %u %u\n",dram[i]->id, - dram[i]->n_cmd_partial?(dram[i]->ave_mrqs_partial/dram[i]->n_cmd_partial ):0); - - // utilization and efficiency - gzprintf(visualizer_file,"dramutil: %u %u\n", - dram[i]->id,dram[i]->n_cmd_partial?100*dram[i]->bwutil_partial/dram[i]->n_cmd_partial:0); - gzprintf(visualizer_file,"drameff: %u %u\n", - dram[i]->id,dram[i]->n_activity_partial?100*dram[i]->bwutil_partial/dram[i]->n_activity_partial:0); - - // reset for next interval - dram[i]->bwutil_partial = 0; - dram[i]->n_activity_partial = 0; - dram[i]->ave_mrqs_partial = 0; - dram[i]->n_cmd_partial = 0; - dram[i]->n_nop_partial = 0; - dram[i]->n_act_partial = 0; - dram[i]->n_pre_partial = 0; - dram[i]->n_req_partial = 0; - } + for (unsigned i=0;i<m_n_shader;i++) + m_sc[i]->new_cache_window(); - // dram access type classification - for (i=0;i<gpu_n_mem;i++) { - unsigned int j; - for (j = 0; j < gpu_mem_n_bk; j++) { - gzprintf(visualizer_file,"dramglobal_acc_r: %u %u %u\n", dram[i]->id, j, - mem_access_type_stats[GLOBAL_ACC_R][dram[i]->id][j]); - gzprintf(visualizer_file,"dramglobal_acc_w: %u %u %u\n", dram[i]->id, j, - mem_access_type_stats[GLOBAL_ACC_W][dram[i]->id][j]); - gzprintf(visualizer_file,"dramlocal_acc_r: %u %u %u\n", dram[i]->id, j, - mem_access_type_stats[LOCAL_ACC_R][dram[i]->id][j]); - gzprintf(visualizer_file,"dramlocal_acc_w: %u %u %u\n", dram[i]->id, j, - mem_access_type_stats[LOCAL_ACC_W][dram[i]->id][j]); - gzprintf(visualizer_file,"dramconst_acc_r: %u %u %u\n", dram[i]->id, j, - mem_access_type_stats[CONST_ACC_R][dram[i]->id][j]); - gzprintf(visualizer_file,"dramtexture_acc_r: %u %u %u\n", dram[i]->id, j, - mem_access_type_stats[TEXTURE_ACC_R][dram[i]->id][j]); - } - } + for (unsigned i=0;i<m_n_mem;i++) + m_memory_partition_unit[i]->visualizer_print(visualizer_file); // overall cache miss rates - gzprintf(visualizer_file, "Lonetexturemiss: %d\n", L1_texture_miss); - gzprintf(visualizer_file, "Loneconstmiss: %d\n", L1_const_miss); - gzprintf(visualizer_file, "Lonereadmiss: %d\n", L1_read_miss); - gzprintf(visualizer_file, "Lonewritemiss: %d\n", L1_write_miss); - gzprintf(visualizer_file, "Ltwowritemiss: %d\n", L2_write_miss); - gzprintf(visualizer_file, "Ltwowritehit: %d\n", L2_write_hit); - gzprintf(visualizer_file, "Ltworeadmiss: %d\n", L2_read_miss); - gzprintf(visualizer_file, "Ltworeadhit: %d\n", L2_read_hit); + gzprintf(visualizer_file, "Lonetexturemiss: %d\n", m_shader_stats->L1_texture_miss); + gzprintf(visualizer_file, "Loneconstmiss: %d\n", m_shader_stats->L1_const_miss); + gzprintf(visualizer_file, "Lonereadmiss: %d\n", m_shader_stats->L1_read_miss); + gzprintf(visualizer_file, "Lonewritemiss: %d\n", m_shader_stats->L1_write_miss); + gzprintf(visualizer_file, "Ltwowritemiss: %d\n", m_memory_stats->L2_write_miss); + gzprintf(visualizer_file, "Ltwowritehit: %d\n", m_memory_stats->L2_write_hit); + gzprintf(visualizer_file, "Ltworeadmiss: %d\n", m_memory_stats->L2_read_miss); + gzprintf(visualizer_file, "Ltworeadhit: %d\n", m_memory_stats->L2_read_hit); // latency stats - if (num_mfs) { - gzprintf(visualizer_file, "averagemflatency: %lld\n", mf_total_lat/num_mfs); + if (m_memory_stats->num_mfs) { + gzprintf(visualizer_file, "averagemflatency: %lld\n", m_memory_stats->mf_total_lat/m_memory_stats->num_mfs); } // other parameters for graphing gzprintf(visualizer_file, "globalcyclecount: %lld\n", gpu_sim_cycle); gzprintf(visualizer_file, "globalinsncount: %lld\n", gpu_sim_insn); gzprintf(visualizer_file, "globaltotinsncount: %lld\n", gpu_tot_sim_insn); - gzprintf(visualizer_file, "gpucompletedthreads: %lld\n", gpu_completed_thread); + gzprintf(visualizer_file, "gpucompletedthreads: %lld\n", m_shader_stats->gpu_completed_thread); gzprintf(visualizer_file, "gpgpunsentwrites: %d\n", gpgpu_n_sent_writes); gzprintf(visualizer_file, "gpgpunprocessedwrites: %d\n", gpgpu_n_processed_writes); - gzprintf(visualizer_file, "gpgpu_n_cache_bkconflict: %d\n", gpgpu_n_cache_bkconflict); - gzprintf(visualizer_file, "gpgpu_n_shmem_bkconflict: %d\n", gpgpu_n_shmem_bkconflict); - gzprintf(visualizer_file, "gpu_stall_by_MSHRwb: %d\n", gpu_stall_by_MSHRwb); + gzprintf(visualizer_file, "gpgpu_n_cache_bkconflict: %d\n", m_shader_stats->gpgpu_n_cache_bkconflict); + gzprintf(visualizer_file, "gpgpu_n_shmem_bkconflict: %d\n", m_shader_stats->gpgpu_n_shmem_bkconflict); + gzprintf(visualizer_file, "gpu_stall_by_MSHRwb: %d\n", m_shader_stats->gpu_stall_by_MSHRwb); // warp divergence breakdown static unsigned int *last_shader_cycle_distro = NULL; if (!last_shader_cycle_distro) - last_shader_cycle_distro = (unsigned int*) calloc(warp_size + 3, sizeof(unsigned int)); + last_shader_cycle_distro = (unsigned int*) calloc(m_shader_config->warp_size + 3, sizeof(unsigned int)); time_vector_print_interval2gzfile(visualizer_file); gzprintf(visualizer_file, "WarpDivergenceBreakdown:"); unsigned int total=0; - unsigned int cf = (gpgpu_warpdistro_shader==-1)?gpu_n_shader:1; - gzprintf(visualizer_file, " %d", (shader_cycle_distro[0] - last_shader_cycle_distro[0]) / cf ); - gzprintf(visualizer_file, " %d", (shader_cycle_distro[2] - last_shader_cycle_distro[2]) / cf ); - for (i=0; i<warp_size+3; i++) { + unsigned int cf = (m_shader_config->gpgpu_warpdistro_shader==-1)?m_n_shader:1; + gzprintf(visualizer_file, " %d", (m_shader_stats->shader_cycle_distro[0] - last_shader_cycle_distro[0]) / cf ); + gzprintf(visualizer_file, " %d", (m_shader_stats->shader_cycle_distro[2] - last_shader_cycle_distro[2]) / cf ); + for (unsigned i=0; i<m_shader_config->warp_size+3; i++) { if ( i>=3 ) { - total += (shader_cycle_distro[i] - last_shader_cycle_distro[i]); - if ( ((i-3) % (warp_size/8)) == ((warp_size/8)-1) ) { + total += (m_shader_stats->shader_cycle_distro[i] - last_shader_cycle_distro[i]); + if ( ((i-3) % (m_shader_config->warp_size/8)) == ((m_shader_config->warp_size/8)-1) ) { gzprintf(visualizer_file, " %d", total / cf ); total=0; } } - last_shader_cycle_distro[i] = shader_cycle_distro[i]; + last_shader_cycle_distro[i] = m_shader_stats->shader_cycle_distro[i]; } gzprintf(visualizer_file,"\n"); @@ -535,12 +473,6 @@ void time_vector_print(void) { g_my_time_vector->print_dist(); } - -void time_vector_print_interval2file(FILE *outfile) { - g_my_time_vector->print_to_file(outfile); -} - - void time_vector_print_interval2gzfile(gzFile outfile) { g_my_time_vector->print_to_gzfile(outfile); } diff --git a/src/gpgpu-sim/visualizer.h b/src/gpgpu-sim/visualizer.h index 19e2d2a..0d9424a 100644 --- a/src/gpgpu-sim/visualizer.h +++ b/src/gpgpu-sim/visualizer.h @@ -66,7 +66,7 @@ #include <zlib.h> void visualizer_options(class OptionParser *opp); -void visualizer_printstat(); +void visualizer_printstat( class shader_core_ctx **sc, unsigned n_shader, class dram_t **dram, unsigned n_mem ); void time_vector_create(int ld_size,int st_size); void time_vector_print(void); void time_vector_update(unsigned int uid,int slot ,long int cycle,int type); diff --git a/src/gpgpu-sim/warp_tracker.cc b/src/gpgpu-sim/warp_tracker.cc index d701c8f..44cbbc6 100644 --- a/src/gpgpu-sim/warp_tracker.cc +++ b/src/gpgpu-sim/warp_tracker.cc @@ -70,87 +70,22 @@ using namespace std; - -void register_cta_thread_exit(shader_core_ctx_t *shader, int cta_num ); - /* * Constructor for warp_tracker_pool. * * Resizes the warp_tracker map and pool and allocates empty warp_trackers. * * @param tid_in Array of thread id's corresponding to a warp - * @param *shd Pointer to the shader core - * - * @return Pointer to a warp_tracker - */ -warp_tracker_pool::warp_tracker_pool(unsigned gpu_n_shader, unsigned gpu_n_thread_per_shader) { - this->gpu_n_shader = gpu_n_shader; - this->gpu_n_thread_per_shader = gpu_n_thread_per_shader; - - // Resize the warp tracker map - warp_tracker_map.resize(gpu_n_shader); - for(unsigned i=0; i<gpu_n_shader; i++) { - warp_tracker_map[i].resize(gpu_n_thread_per_shader); - } - - // Create a pool of warp_trackers - warp_tracker_list.resize(gpu_n_shader * gpu_n_thread_per_shader); - - // Add all warp_trackers to the list of free warp_trackers - std::list<warp_tracker>::iterator it; - for(it=warp_tracker_list.begin(); it!=warp_tracker_list.end(); it++) - warp_tracker_free_list.push_back(&(*it)); - -} - -/* - * Fetch a free warp_tracker from the pool of warp_trackers. Assigns the warp_tracker to - * the input warp. - * - * If there are no free warp_trackers in the pool, the pool is extended by allocating more - * warp_trackers. - * - * @param tid_in Array of thread id's corresponding to a warp - * @param *shd Pointer to the shader core - * - * @return Pointer to a warp_tracker - */ -warp_tracker* warp_tracker_pool::alloc_warp_tracker( int *tid_in, shader_core_ctx_t *shd, address_type pc ) { - // If no free warp trackers are available, allocate some more - if(warp_tracker_free_list.empty()) { - printf("warp_tracker_list empty (size=%d) - allocating new warp_trackers\n", size()); - fflush(stdout); - // Warp tracker list is empty, resize the list - unsigned previous_size = warp_tracker_list.size(); - warp_tracker_list.resize( previous_size + this->gpu_n_thread_per_shader); - - // Add newly allocated warp trackers to list of free warp trackers - std::list<warp_tracker>::iterator it = warp_tracker_list.begin(); - for(unsigned i=0; i<previous_size; i++) - it++; // Increment iterator - for(; it!=warp_tracker_list.end(); it++) - warp_tracker_free_list.push_back(&(*it)); - } - - assert(!warp_tracker_free_list.empty()); - // Fetch a free warp_tracker - warp_tracker* wpt = warp_tracker_free_list.front(); - warp_tracker_free_list.pop_front(); - wpt->set_warp(tid_in, shd, pc); - - return wpt; -} - -/* - * Free the warp_tracker. - * - * Puts the warp_tracker back into the pool of free warp_trackers. - * - * @param wpt Pointer to a warp_tracker + * @param *my_shader Pointer to the shader core * */ -void warp_tracker_pool::free_warp_tracker(warp_tracker* wpt) { - warp_tracker_free_list.push_back(wpt); +warp_tracker_pool::warp_tracker_pool(class shader_core_ctx *my_shader) +{ + m_shader=my_shader; + const shader_core_config *config = my_shader->get_config(); + gpu_n_thread_per_shader = config->n_thread_per_shader; + warp_size = config->warp_size; + warp_tracker_map.resize(gpu_n_thread_per_shader); } /* @@ -163,24 +98,15 @@ void warp_tracker_pool::free_warp_tracker(warp_tracker* wpt) { * @param *shd Pointer to the shader core * */ -void warp_tracker_pool::wpt_register_warp( int *tid_in, shader_core_ctx_t *shd, address_type pc) +void warp_tracker_pool::wpt_register_warp( int *tid_in, address_type pc, unsigned n_thd, unsigned warp_size ) { - int sid = shd->sid; - unsigned i; - int n_thd = 0; - for (i=0; i<warp_size; i++) { - if (tid_in[i] >= 0) n_thd++; - } - - if (!n_thd) return; - - warp_tracker *wpt = this->alloc_warp_tracker(tid_in, shd, pc); - + assert(n_thd); + warp_tracker *wpt = new warp_tracker(tid_in,pc,warp_size); // assign the new warp_tracker to warp_tracker_map - for (i=0; i<warp_size; i++) { + for (unsigned i=0; i<warp_size; i++) { if (tid_in[i] >= 0) { - assert( map_get_warp_tracker(sid,tid_in[i],pc) == NULL ); - map_set_warp_tracker(sid, tid_in[i], pc, wpt); + assert( map_get_warp_tracker(tid_in[i],pc) == NULL ); + map_set_warp_tracker(tid_in[i], pc, wpt); } } } @@ -193,10 +119,9 @@ void warp_tracker_pool::wpt_register_warp( int *tid_in, shader_core_ctx_t *shd, * * @return Returns true is all threads in the warp have completed. */ -int warp_tracker_pool::wpt_signal_avail( int tid, shader_core_ctx_t *shd, address_type pc ) +int warp_tracker_pool::wpt_signal_avail( int tid, address_type pc ) { - int sid = shd->sid; - warp_tracker *wpt = map_get_warp_tracker(sid,tid,pc); + warp_tracker *wpt = map_get_warp_tracker(tid,pc); assert(wpt != NULL); @@ -215,22 +140,13 @@ int warp_tracker_pool::wpt_signal_avail( int tid, shader_core_ctx_t *shd, addres * by number of active threads. * * @param tid Thread that is exiting - * @param *shd Pointer to the shader core * */ -void warp_tracker_pool::wpt_deregister_warp( int tid, shader_core_ctx_t *shd, address_type pc ) { - int sid = shd->sid; - warp_tracker *wpt = map_get_warp_tracker(sid,tid,pc); +void warp_tracker_pool::wpt_deregister_warp( int tid, address_type pc ) { + warp_tracker *wpt = map_get_warp_tracker(tid,pc); assert(wpt != NULL); - - // the warp is ready to be fetched again, remove this warp_tracker - for (unsigned i=0; i<warp_size; i++) { - if (wpt->tid[i] >= 0) { - map_clear_warp_tracker(sid,wpt->tid[i],pc); - } - } - - free_warp_tracker( wpt ); + map_clear_warp_tracker(wpt); + delete wpt; } @@ -241,30 +157,26 @@ void warp_tracker_pool::wpt_deregister_warp( int tid, shader_core_ctx_t *shd, ad * threads and removed the warp from warp tracker. * * @param tid Thread that is exiting - * @param *shd Pointer to the shader core * * @return The warp's mask of active threads. */ -int warp_tracker_pool::wpt_signal_complete( int tid, shader_core_ctx_t *shd, address_type pc ) +int warp_tracker_pool::wpt_signal_complete( int tid, address_type pc ) { - int sid = shd->sid; - warp_tracker *wpt = map_get_warp_tracker(sid,tid,pc); + warp_tracker *wpt = map_get_warp_tracker(tid,pc); assert(wpt != NULL); // signal the warp tracker if (wpt->complete_thd(tid)) { // if the warp has completed execution, remove this warp_tracker + map_clear_warp_tracker(wpt); int warp_mask = 0; for (unsigned i=0; i<warp_size; i++) { - if (wpt->tid[i] >= 0) { - register_cta_thread_exit(shd, wpt->tid[i] ); - map_clear_warp_tracker(sid,wpt->tid[i],pc); + if (wpt->tid(i) >= 0) { + m_shader->register_cta_thread_exit( wpt->tid(i) ); warp_mask |= (1 << i); } } - - free_warp_tracker( wpt ); - + delete wpt; return warp_mask; } else { return 0; @@ -276,373 +188,84 @@ int warp_tracker_pool::wpt_signal_complete( int tid, shader_core_ctx_t *shd, add * * Checks if any pc of the given tid maps to a warp_tracker * - * @param *shd Pointer to the shader core * @param tid Thread to check * * @return True is thread is being tracked */ -bool warp_tracker_pool::wpt_thread_in_wpt(shader_core_ctx *shd, int tid) { - int sid = shd->sid; +bool warp_tracker_pool::wpt_thread_in_wpt(int tid) { std::map<address_type, warp_tracker*>::iterator it; - for(it=warp_tracker_map[sid][tid].begin(); it!=warp_tracker_map[sid][tid].end(); it++) + for(it=warp_tracker_map[tid].begin(); it!=warp_tracker_map[tid].end(); it++) if((*it).second != NULL) return true; return false; } - - -warp_tracker_pool& get_warp_tracker_pool(){ - static warp_tracker_pool* wpt_pool = new warp_tracker_pool(gpu_n_shader, gpu_n_thread_per_shader); - return *wpt_pool; -} - - -//------------------------------------------------------------------------------- - -/* - -static warp_tracker ***warp_tracker_map; -static unsigned **g_warp_tracker_map_setl_cycle; -static warp_tracker *warp_tracker_pool = NULL; -static list<warp_tracker*> free_wpt; - -warp_tracker* alloc_warp_tracker( int *tid_in, shader_core_ctx_t *shd ) -{ - assert(!free_wpt.empty()); - warp_tracker* wpt = free_wpt.front(); - free_wpt.pop_front(); - - wpt->set_warp(tid_in, shd); - - return wpt; -} - -void free_warp_tracker(warp_tracker* wpt) -{ - free_wpt.push_back(wpt); -} - -void init_warp_tracker( ) -{ - unsigned int i; - - warp_tracker_map = (warp_tracker ***)calloc(gpu_n_shader, sizeof(warp_tracker **)); - g_warp_tracker_map_setl_cycle = (unsigned**)calloc(gpu_n_shader, sizeof(unsigned*)); - for (i=0; i<gpu_n_shader; i++) { - warp_tracker_map[i] = (warp_tracker **)calloc(gpu_n_thread_per_shader, sizeof(warp_tracker *)); - g_warp_tracker_map_setl_cycle[i] = (unsigned*)calloc(gpu_n_thread_per_shader, sizeof(unsigned)); - } - - // max possible number of warps is just when each thread has its own warp - warp_tracker_pool = new warp_tracker[gpu_n_shader * gpu_n_thread_per_shader]; - printf("%d %d %d %d\n", warp_size, gpu_n_shader, gpu_n_thread_per_shader, - warp_size * gpu_n_shader * gpu_n_thread_per_shader); - for (i=0; i<gpu_n_shader*gpu_n_thread_per_shader; i++) { - free_wpt.push_back(&(warp_tracker_pool[i])); - } - printf("%zd\n", free_wpt.size()); -} - -void wpt_register_warp( int *tid_in, shader_core_ctx_t *shd ) -{ - int sid = shd->sid; - unsigned i; - int n_thd = 0; - for (i=0; i<warp_size; i++) { - if (tid_in[i] >= 0) n_thd++; - } - - if (!n_thd) return; - - warp_tracker *wpt = alloc_warp_tracker(tid_in, shd); - - // assign the new warp_tracker to warp_tracker_map - for (i=0; i<warp_size; i++) { - if (tid_in[i] >= 0) { - assert( warp_tracker_map[sid][tid_in[i]] == NULL ); - warp_tracker_map[sid][tid_in[i]] = wpt; - g_warp_tracker_map_setl_cycle[sid][tid_in[i]] = gpu_tot_sim_cycle + gpu_sim_cycle; - } - } -} - -int wpt_signal_avail( int tid, shader_core_ctx_t *shd ) -{ - int sid = shd->sid; - warp_tracker *wpt = warp_tracker_map[sid][tid]; - assert(wpt != NULL); - - - // signal the warp tracker - if (wpt->avail_thd()) { - return 1; - } else { - return 0; - } -} - -// Unlock a warp -void wpt_unlock_threads( int tid, shader_core_ctx_t *shd ) { - int sid = shd->sid; - warp_tracker *wpt = warp_tracker_map[sid][tid]; - assert(wpt != NULL); - - int thd_unlocked = 0; - // Unlock - for (unsigned i=0; i<warp_size; i++) { - if (wpt->tid[i] >= 0) { - shd->thread[wpt->tid[i]].avail4fetch++; - assert(shd->thread[wpt->tid[i]].avail4fetch <= 1); - assert( shd->warp[wpt->tid[i]/warp_size].n_avail4fetch < warp_size ); - shd->warp[wpt->tid[i]/warp_size].n_avail4fetch++; - thd_unlocked = 1; - } - } - - if (shd->model == POST_DOMINATOR || shd->model == NO_RECONVERGE) { - // Do nothing - } else { - // For this case, submit to commit_queue - if (shd->using_commit_queue && thd_unlocked) { - int *tid_unlocked = alloc_commit_warp(); - memcpy(tid_unlocked, wpt->tid, sizeof(int)*warp_size); - dq_push(shd->thd_commit_queue,(void*)tid_unlocked); - } - } - - // the warp is ready to be fetched again, remove this warp_tracker - for (unsigned i=0; i<warp_size; i++) { - if (wpt->tid[i] >= 0) { - warp_tracker_map[sid][wpt->tid[i]] = NULL; - g_warp_tracker_map_setl_cycle[sid][wpt->tid[i]] = gpu_tot_sim_cycle + gpu_sim_cycle; - } - } - - free_warp_tracker( wpt ); -} - -*/ - -/* - * Signal that the a thread is done and is exiting (exit instruction) - * - * Marks a thread as completed. If all threads in the warp have completed, call register_cta_thread_exit on all - * threads and removed the warp from warp tracker. - * - * @param tid Thread that is exiting - * @param *shd Pointer to the shader core - * - * @return The warp's mask of active threads. - */ -// - -/* -int wpt_signal_complete( int tid, shader_core_ctx_t *shd ) -{ - int sid = shd->sid; - warp_tracker *wpt = warp_tracker_map[sid][tid]; - assert(wpt != NULL); - - // signal the warp tracker - if (wpt->complete_thd(tid)) { - // if the warp has completed execution, remove this warp_tracker - int warp_mask = 0; - for (unsigned i=0; i<warp_size; i++) { - if (wpt->tid[i] >= 0) { - register_cta_thread_exit(shd, wpt->tid[i] ); - warp_tracker_map[sid][wpt->tid[i]] = NULL; - g_warp_tracker_map_setl_cycle[sid][wpt->tid[i]] = gpu_tot_sim_cycle + gpu_sim_cycle; - warp_mask |= (1 << i); - } - } - - free_warp_tracker( wpt ); - - return warp_mask; - } else { - return 0; - } -} -*/ - //------------------------------------------------------------------------------------ -class thread_pc_tracker_class { -public: - address_type *thd_pc; // tracks the pc of each thread - map<address_type, unsigned> pc_count; - unsigned acc_pc_count; - int simd_width; - static map<unsigned, unsigned> histogram; - - thread_pc_tracker_class( ) { - this->acc_pc_count = 0; - this->simd_width = 0; - this->thd_pc = NULL; - } - - thread_pc_tracker_class(int simd_width, int thread_count) { - this->acc_pc_count = 0; - this->simd_width = simd_width; - this->thd_pc = new address_type[thread_count]; - memset( this->thd_pc, 0, sizeof(address_type)*thread_count); - } - - void add_threads( int *tid, address_type pc ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] != -1) { - pc_count[pc] += 1; // automatically create a new entry if not exist - thd_pc[tid[i]] = pc; - } - } - } - - void sub_threads( int *tid ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] != -1) { - address_type pc = thd_pc[tid[i]]; - if (pc == 0) break; - pc_count[pc] -= 1; - assert((int)pc_count[pc] >= 0); - if (pc_count[pc] == 0) pc_count.erase(pc); // manually erasing entries with 0 count - } - } - } - - void update_acc_count( ) { - acc_pc_count += pc_count.size(); - histogram[pc_count.size()] += 1; - } - - void set_threads_pc ( int *tid, address_type pc ) { - sub_threads(tid); - add_threads(tid, pc); - update_acc_count( ); - } - - unsigned get_acc_pc_count( ) { return acc_pc_count;} - - unsigned count( ) { return pc_count.size();} - - static void histo_print( FILE* fout ) { - if (histogram.empty()) return; // do not output anything if the histogram is empty - map<unsigned, unsigned>::iterator i; - fprintf(fout, "Thread PC Histogram: "); - for (i = histogram.begin(); i != histogram.end(); i++) { - fprintf(fout, "%d:%d ", i->first, i->second); - } - fprintf(fout, "\n"); - } -}; - -map<unsigned, unsigned> thread_pc_tracker_class::histogram; +map<unsigned, unsigned> thread_pc_tracker::histogram; -thread_pc_tracker_class *thread_pc_tracker = NULL; +thread_pc_tracker *thread_pc_tracker = NULL; void print_thread_pc_histogram( FILE *fout ) { - thread_pc_tracker_class::histo_print(fout); + thread_pc_tracker::histo_print(fout); } -void print_thread_pc( FILE *fout ) +void print_thread_pc( FILE *fout, unsigned n_shader ) { fprintf(fout, "SHD_PC_C: "); - for (unsigned i=0; i<gpu_n_shader; i++) { + for (unsigned i=0; i<n_shader; i++) { fprintf(fout, "%d ", thread_pc_tracker[i].get_acc_pc_count() ); } fprintf(fout, "\n"); } -void track_thread_pc( int shader_id, int *tid, address_type pc ) -{ - if (!thread_pc_tracker) { - thread_pc_tracker = new thread_pc_tracker_class[gpu_n_shader]; - for (unsigned i=0; i<gpu_n_shader; i++) { - thread_pc_tracker[i] = thread_pc_tracker_class(warp_size, gpu_n_thread_per_shader); - } - } - thread_pc_tracker[shader_id].set_threads_pc( tid, pc ); -} - -//------------------------------------------------------------------------------------ - -static int *commit_warp_pool = NULL; -static queue<int*> free_commit_warp_q; - -void init_commit_warp( ) -{ - unsigned int num_warp = warp_size * gpu_n_shader * gpu_n_thread_per_shader; - commit_warp_pool = new int[num_warp]; - for (unsigned int i=0; i<num_warp; i+=warp_size) { - free_commit_warp_q.push(&(commit_warp_pool[i])); - } -} - -int* alloc_commit_warp( ) -{ - if (!commit_warp_pool) { - init_commit_warp( ); - } - - assert(!free_commit_warp_q.empty()); - int *new_commit_warp = free_commit_warp_q.front(); - free_commit_warp_q.pop(); - - return new_commit_warp; -} - -void free_commit_warp( int *commit_warp ) -{ - free_commit_warp_q.push(commit_warp); -} - // uncomment to enable checking for warp consistency // #define CHECK_WARP_CONSISTENCY -void check_stage_pcs( shader_core_ctx_t *shader, unsigned stage ) +void shader_core_ctx::check_stage_pcs( unsigned stage ) { #ifdef CHECK_WARP_CONSISTENCY address_type inst_pc = (address_type)-1; unsigned tid; - if( shader->model == MIMD ) + if( m_config->model == MIMD ) return; std::set<unsigned> tids; - for ( int i = 0; i < pipe_simd_width; i++) { - if (shader->pipeline_reg[i][stage].hw_thread_id == -1 ) + for ( int i = 0; i < m_config->warp_size; i++) { + if (m_pipeline_reg[i][stage].hw_thread_id == -1 ) continue; if ( inst_pc == (address_type)-1 ) - inst_pc = shader->pipeline_reg[i][stage].pc; - tid = shader->pipeline_reg[i][stage].hw_thread_id; + inst_pc = m_pipeline_reg[i][stage].pc; + tid = m_pipeline_reg[i][stage].hw_thread_id; assert( tids.find(tid) == tids.end() ); tids.insert(tid); - assert( inst_pc == shader->pipeline_reg[i][stage].pc ); + assert( inst_pc == m_pipeline_reg[i][stage].pc ); } #endif } -void check_pm_stage_pcs( shader_core_ctx_t *shader, unsigned stage ) +void shader_core_ctx::check_pm_stage_pcs( unsigned stage ) { #ifdef CHECK_WARP_CONSISTENCY address_type inst_pc = (address_type)-1; unsigned tid; - if( shader->model == MIMD ) + if( m_config->model == MIMD ) return; std::set<unsigned> tids; - for (int i = 0; i < pipe_simd_width; i++) { - if (shader->pre_mem_pipeline[i][stage].hw_thread_id == -1 ) + for (int i = 0; i < m_config->warp_size; i++) { + if (pre_mem_pipeline[i][stage].hw_thread_id == -1 ) continue; if ( inst_pc == (address_type)-1 ) - inst_pc = shader->pre_mem_pipeline[i][stage].pc; - tid = shader->pre_mem_pipeline[i][stage].hw_thread_id; + inst_pc = pre_mem_pipeline[i][stage].pc; + tid = pre_mem_pipeline[i][stage].hw_thread_id; assert( tids.find(tid) == tids.end() ); tids.insert(tid); - assert( inst_pc == shader->pre_mem_pipeline[i][stage].pc ); + assert( inst_pc == pre_mem_pipeline[i][stage].pc ); } #endif } diff --git a/src/gpgpu-sim/warp_tracker.h b/src/gpgpu-sim/warp_tracker.h index 1e2e5e0..8397a81 100644 --- a/src/gpgpu-sim/warp_tracker.h +++ b/src/gpgpu-sim/warp_tracker.h @@ -63,176 +63,199 @@ * Vancouver, BC V6T 1Z4 */ -#include <vector> -#include <map> -#include <list> - #ifndef warp_tracker_h_INCLUDED #define warp_tracker_h_INCLUDED -#ifdef __cplusplus - - #include <cstdio> - #include <cstdlib> - #include <cstring> - #include <cassert> - #include <map> - #include <list> - #include <deque> - #include <queue> - -#endif +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cassert> +#include <map> +#include <list> +#include <deque> +#include <queue> +#include <vector> +#include <map> +#include <list> #include "../abstract_hardware_model.h" #include "shader.h" -extern unsigned int warp_size; -extern unsigned int gpu_n_shader; -extern unsigned int gpu_n_thread_per_shader; - -//void init_warp_tracker( ); - -//void wpt_register_warp( int *tid_in, shader_core_ctx_t *shd ); - -//int wpt_signal_avail( int tid, shader_core_ctx_t *shd ); - -//void wpt_unlock_threads( int tid, shader_core_ctx_t *shd ); - -//int wpt_signal_complete( int tid, shader_core_ctx_t *shd ); - void print_thread_pc_histogram( FILE *fout ); -void print_thread_pc( FILE *fout ); -void track_thread_pc( int shader_id, int *tid, address_type pc ); - -int* alloc_commit_warp( ); -void free_commit_warp( int *commit_warp ); +void print_thread_pc( FILE *fout, unsigned n_shader ); class warp_tracker { public: - std::vector<int> tid; - - int n_thd; // total number of threads in this warp - int n_notavail; // number of threads still not available - shader_core_ctx_t *shd; // reference to shader core - address_type pc; - - warp_tracker () { - tid.resize(warp_size,-1); - - n_thd = 0; - n_notavail = 0; - shd = NULL; + warp_tracker( int *tid, address_type pc, unsigned warp_size ) + { + // makes a copy of pc and thread ids in warp + m_pc = pc; + m_n_thd = 0; + m_warp_size=warp_size; + m_tid.reserve(warp_size); + std::copy(tid, tid+warp_size, m_tid.begin()); + for (unsigned i=0; i<warp_size; i++) + if (tid[i] >= 0) m_n_thd++; + m_n_notavail = m_n_thd; } - void print_info(){ - printf("sid=%d ", shd->sid); - - printf("tid=["); - for(unsigned i=0; i<warp_size; i++) - if(tid[i] > -1) - printf("%d ", tid[i]); + void print_info( unsigned sid ) const + { + printf("sid=%d tid=[", sid); + for(unsigned i=0; i<m_tid.size(); i++) + if(m_tid[i] > -1) printf("%d ", m_tid[i]); printf("]\n"); } + unsigned warp_size() const { return m_warp_size; } + address_type pc() const { return m_pc; } + int tid(unsigned i) const { return m_tid[i]; } - void copy_tid( int *tid ) { - std::copy(tid, tid+warp_size, this->tid.begin()); + bool avail_thd() + { + // signal that this thread is available for fetch + // if all threads in the warp are available, change all their status + // and return true + assert( m_n_notavail > 0 ); + m_n_notavail--; + return (m_n_notavail==0); } - // set the warp to be consist of the given threads - void set_warp ( int *tid, shader_core_ctx_t *shd, address_type pc) { - copy_tid(tid); - - this->n_thd = 0; - this->n_notavail = 0; - for (unsigned i=0; i<warp_size; i++) { - if (this->tid[i] >= 0) { - this->n_thd++; - } - } - this->n_notavail = this->n_thd; - this->shd = shd; - this->pc = pc; - } - - // signal that this thread is available for fetch - // if all threads in the warp are available, change all their status - // and return true - bool avail_thd ( ) { - n_notavail--; - return (n_notavail==0); - } - - // a bookkeeping method to allow a warp to be deallocated - // when its threads have finished executing. - bool complete_thd ( int tid_in ) { - n_notavail--; - if (n_notavail) { + bool complete_thd( int tid_in ) + { + // a bookkeeping method to allow a warp to be deallocated + // when its threads have finished executing. + assert( m_n_notavail > 0 ); + m_n_notavail--; + if (m_n_notavail) { return false; } else { return true; } } + +private: + address_type m_pc; + std::vector<int> m_tid; + int m_n_thd; // total number of threads in this warp with active mask set to enabled + int m_n_notavail; // number of threads waiting (preventing this warp from being issued again) + unsigned m_warp_size; }; -//------------------------------------------------------------------- -class warp_tracker_pool -{ - private: - unsigned gpu_n_shader; - unsigned gpu_n_thread_per_shader; +class warp_tracker_pool { +public: + warp_tracker_pool( class shader_core_ctx *my_shader ); + + void wpt_register_warp( int *tid_in, address_type pc, unsigned n_thread_in_warp, unsigned warp_size ); + int wpt_signal_avail( int tid, address_type pc ); + void wpt_deregister_warp( int tid, address_type pc ); + int wpt_signal_complete( int tid, address_type pc ); + bool wpt_thread_in_wpt( int tid ); - // Warp tracker map: a vector (index shader id) of vectors (index thread id) of maps (index pc) - std::vector< std::vector< std::map<address_type, warp_tracker*> > > warp_tracker_map; +private: + warp_tracker* map_get_warp_tracker(int tid, address_type pc) { + // Returns NULL pointer if no warp_tracker assigned + if(warp_tracker_map[tid].find(pc) == warp_tracker_map[tid].end()) + return NULL; + return warp_tracker_map[tid][pc]; + } - // Pool of warp trackers - std::list<warp_tracker> warp_tracker_list; + void map_set_warp_tracker(int tid, address_type pc, warp_tracker* wpt) { + // Make sure that warp tracker is not already assigned here + if(warp_tracker_map[tid].find(pc) != warp_tracker_map[tid].end()) + assert(warp_tracker_map[tid][pc] == NULL); + warp_tracker_map[tid][pc] = wpt; + } - // List to keep track of free warp trackers - std::list<warp_tracker*> warp_tracker_free_list; + void map_clear_warp_tracker( warp_tracker *wpt ) { + // Make sure that warp tracker was previously assigned + address_type pc = wpt->pc(); + for (unsigned i=0; i<wpt->warp_size(); i++) { + int tid = wpt->tid(i); + if (tid >= 0) { + assert(warp_tracker_map[tid].find(pc) != warp_tracker_map[tid].end()); + assert(warp_tracker_map[tid][pc] != NULL); + warp_tracker_map[tid][pc] = NULL; + } + } + } - warp_tracker* map_get_warp_tracker(int sid, int tid, address_type pc) { - // Return NULL pointer if no warp_tracker assigned - if(warp_tracker_map[sid][tid].find(pc) == warp_tracker_map[sid][tid].end()) - return NULL; +// data - return warp_tracker_map[sid][tid][pc]; - } + class shader_core_ctx *m_shader; + unsigned gpu_n_thread_per_shader; + unsigned warp_size; - void map_set_warp_tracker(int sid, int tid, address_type pc, warp_tracker* wpt) { - // Make sure that warp tracker is not already assigned here - if(warp_tracker_map[sid][tid].find(pc) != warp_tracker_map[sid][tid].end()) - assert(warp_tracker_map[sid][tid][pc] == NULL); + // Warp tracker map: vector (index thread id) of maps (index pc) + std::vector< std::map<address_type, warp_tracker*> > warp_tracker_map; +}; + +class thread_pc_tracker { +public: + address_type *thd_pc; // tracks the pc of each thread + std::map<address_type, unsigned> pc_count; + unsigned acc_pc_count; + int simd_width; + static std::map<unsigned, unsigned> histogram; // static so automatically aggregated across cores - warp_tracker_map[sid][tid][pc] = wpt; - } + thread_pc_tracker( ) { + this->acc_pc_count = 0; + this->simd_width = 0; + this->thd_pc = NULL; + } - void map_clear_warp_tracker(int sid, int tid, address_type pc) { - // Make sure that warp tracker was previously assigned - assert(warp_tracker_map[sid][tid].find(pc) != warp_tracker_map[sid][tid].end()); - assert(warp_tracker_map[sid][tid][pc] != NULL); + thread_pc_tracker(int simd_width, int thread_count) { + this->acc_pc_count = 0; + this->simd_width = simd_width; + this->thd_pc = new address_type[thread_count]; + memset( this->thd_pc, 0, sizeof(address_type)*thread_count); + } - warp_tracker_map[sid][tid][pc] = NULL; - } + void add_threads( int *tid, address_type pc ) { + for (int i=0; i<simd_width; i++) { + if (tid[i] != -1) { + pc_count[pc] += 1; // automatically create a new entry if not exist + thd_pc[tid[i]] = pc; + } + } + } - warp_tracker* alloc_warp_tracker( int *tid_in, shader_core_ctx_t *shd, address_type pc ); - void free_warp_tracker(warp_tracker* wpt); + void sub_threads( int *tid ) { + for (int i=0; i<simd_width; i++) { + if (tid[i] != -1) { + address_type pc = thd_pc[tid[i]]; + if (pc == 0) break; + pc_count[pc] -= 1; + assert((int)pc_count[pc] >= 0); + if (pc_count[pc] == 0) pc_count.erase(pc); // manually erasing entries with 0 count + } + } + } - public: - warp_tracker_pool( unsigned gpu_n_shader, unsigned gpu_n_thread_per_shader ); + void update_acc_count( ) { + acc_pc_count += pc_count.size(); + histogram[pc_count.size()] += 1; + } - void wpt_register_warp( int *tid_in, shader_core_ctx_t *shd, address_type pc ); - int wpt_signal_avail( int tid, shader_core_ctx_t *shd, address_type pc ); - void wpt_deregister_warp( int tid, shader_core_ctx_t *shd, address_type pc ); - int wpt_signal_complete( int tid, shader_core_ctx_t *shd, address_type pc ); + void set_threads_pc ( int *tid, address_type pc ) { + sub_threads(tid); + add_threads(tid, pc); + update_acc_count( ); + } - unsigned size() { return warp_tracker_list.size(); } - unsigned free_size() { return warp_tracker_free_list.size(); } + unsigned get_acc_pc_count( ) { return acc_pc_count;} - bool wpt_thread_in_wpt(shader_core_ctx *shd, int tid); + unsigned count( ) { return pc_count.size();} + static void histo_print( FILE* fout ) { + if (histogram.empty()) return; // do not output anything if the histogram is empty + std::map<unsigned, unsigned>::iterator i; + fprintf(fout, "Thread PC Histogram: "); + for (i = histogram.begin(); i != histogram.end(); i++) { + fprintf(fout, "%d:%d ", i->first, i->second); + } + fprintf(fout, "\n"); + } }; -warp_tracker_pool& get_warp_tracker_pool(); - #endif |
