summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim')
-rw-r--r--src/gpgpu-sim/Makefile209
-rw-r--r--src/gpgpu-sim/delayqueue.cc467
-rw-r--r--src/gpgpu-sim/delayqueue.h192
-rw-r--r--src/gpgpu-sim/dram.cc630
-rw-r--r--src/gpgpu-sim/dram.h129
-rw-r--r--src/gpgpu-sim/dram_sched.cc47
-rw-r--r--src/gpgpu-sim/gpu-cache.cc244
-rw-r--r--src/gpgpu-sim/gpu-cache.h36
-rw-r--r--src/gpgpu-sim/gpu-misc.h6
-rw-r--r--src/gpgpu-sim/gpu-sim.cc1583
-rw-r--r--src/gpgpu-sim/gpu-sim.h349
-rw-r--r--src/gpgpu-sim/icnt_wrapper.cc4
-rw-r--r--src/gpgpu-sim/icnt_wrapper.h4
-rw-r--r--src/gpgpu-sim/l2cache.cc940
-rw-r--r--src/gpgpu-sim/l2cache.h301
-rw-r--r--src/gpgpu-sim/mem_fetch.cc106
-rw-r--r--src/gpgpu-sim/mem_fetch.h44
-rw-r--r--src/gpgpu-sim/mem_latency_stat.cc189
-rw-r--r--src/gpgpu-sim/mem_latency_stat.h112
-rw-r--r--src/gpgpu-sim/scoreboard.cc66
-rw-r--r--src/gpgpu-sim/scoreboard.h33
-rw-r--r--src/gpgpu-sim/shader.cc4703
-rw-r--r--src/gpgpu-sim/shader.h1186
-rw-r--r--src/gpgpu-sim/stat-tool.cc7
-rw-r--r--src/gpgpu-sim/stat-tool.h1
-rw-r--r--src/gpgpu-sim/stats.h138
-rw-r--r--src/gpgpu-sim/visualizer.cc154
-rw-r--r--src/gpgpu-sim/visualizer.h2
-rw-r--r--src/gpgpu-sim/warp_tracker.cc471
-rw-r--r--src/gpgpu-sim/warp_tracker.h281
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