diff options
48 files changed, 2240 insertions, 770 deletions
@@ -8,7 +8,7 @@ set print array-indexes set unwindonsignal on define dp - call g_the_gpu->dump_pipeline((0x40|0x4|0x1),$arg0,0) + call GPGPU_Context()->the_gpgpusim->g_the_gpu->dump_pipeline((0x40|0x4|0x1),$arg0,0) end document dp @@ -23,7 +23,7 @@ see the source code for more details) end define dpc - call g_the_gpu->dump_pipeline((0x40|0x4|0x1),$arg0,0) + call GPGPU_Context()->the_gpgpusim->g_the_gpu->dump_pipeline((0x40|0x4|0x1),$arg0,0) continue end @@ -39,7 +39,7 @@ the next cycle. end define dm - call g_the_gpu->dump_pipeline(0x10000|0x10000000,0,$arg0) + call GPGPU_Context()->the_gpgpusim->g_the_gpu->dump_pipeline(0x10000|0x10000000,0,$arg0) end define ptxdis @@ -56,3 +56,8 @@ debug_tools/WatchYourStep/ptxjitplus/gpgpu* debug_tools/WatchYourStep/ptxjitplus/*.old debug_tools/WatchYourStep/ptxjitplus/ptxjitplus debug_tools/WatchYourStep/ptxjitplus/*.ptx + +# Accel-sim packages used for regressions +accel-sim-framework/ +gpu-app-collection/ + diff --git a/.travis.yml b/.travis.yml index 82f0604..2c75e69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,15 +13,26 @@ matrix: - CONFIG=GTX480 - CUDA_INSTALL_PATH=/usr/local/cuda-4.2/ - PTXAS_CUDA_INSTALL_PATH=/usr/local/cuda-4.2/ + - GPUAPPS_ROOT=/home/runner/gpgpu-sim_simulations/benchmarks - services: docker env: - CONFIG=TITANV - CUDA_INSTALL_PATH=/usr/local/cuda-9.1/ - PTXAS_CUDA_INSTALL_PATH=/usr/local/cuda-9.1/ + - GPUAPPS_ROOT=/home/runner/gpgpu-sim_simulations/benchmarks - services: docker env: - CONFIG=TITANV-LOCALXBAR - CUDA_INSTALL_PATH=/usr/local/cuda-9.1/ - PTXAS_CUDA_INSTALL_PATH=/usr/local/cuda-9.1/ + - GPUAPPS_ROOT=/home/runner/gpgpu-sim_simulations/benchmarks -script: docker run -v `pwd`:/home/runner/gpgpu-sim_distribution:rw tgrogers/gpgpu-sim_regress:volta_update /bin/bash -c "./start_torque.sh; chown -R runner /home/runner/gpgpu-sim_distribution; su - runner -c 'export CUDA_INSTALL_PATH=$CUDA_INSTALL_PATH && export PTXAS_CUDA_INSTALL_PATH=$PTXAS_CUDA_INSTALL_PATH && source /home/runner/gpgpu-sim_distribution/setup_environment && make -j -C /home/runner/gpgpu-sim_distribution && cd /home/runner/gpgpu-sim_simulations/ && git pull && /home/runner/gpgpu-sim_simulations/util/job_launching/run_simulations.py -C $CONFIG -B rodinia_2.0-ft -N regress && /home/runner/gpgpu-sim_simulations/util/job_launching/monitor_func_test.py -v -N regress'" +script: + - > + docker run + --env CONFIG=$CONFIG + --env PTXAS_CUDA_INSTALL_PATH=$PTXAS_CUDA_INSTALL_PATH + --env CUDA_INSTALL_PATH=$CUDA_INSTALL_PATH + --env GPUAPPS_ROOT=$GPUAPPS_ROOT + -v `pwd`:/gpgpu-sim:rw tgrogers/gpgpu-sim_regress:volta_update + /bin/bash travis.sh @@ -57,12 +57,12 @@ endif $(shell mkdir -p $(SIM_OBJ_FILES_DIR)/libcuda && echo "const char *g_gpgpusim_build_string=\"$(GPGPUSIM_BUILD)\";" > $(SIM_OBJ_FILES_DIR)/detailed_version) -LIBS = cuda-sim gpgpu-sim_uarch $(INTERSIM) gpgpusimlib +LIBS = cuda-sim gpgpu-sim_uarch $(INTERSIM) gpgpusimlib TARGETS = ifeq ($(shell uname),Linux) - TARGETS += $(SIM_LIB_DIR)/libcudart.so + TARGETS += $(SIM_LIB_DIR)/libcudart.so else # MAC TARGETS += $(SIM_LIB_DIR)/libcudart.dylib endif @@ -143,7 +143,7 @@ no_opencl_support: @echo "Warning: gpgpu-sim is building without opencl support. Make sure NVOPENCL_LIBDIR and NVOPENCL_INCDIR are set" $(SIM_LIB_DIR)/libcudart.so: makedirs $(LIBS) cudalib - g++ -shared -Wl,-soname,libcudart_$(GPGPUSIM_BUILD).so -Wl,--version-script=linux-so-version.txt\ + g++ -shared -Wl,-soname,libcudart.so -Wl,--version-script=linux-so-version.txt\ $(SIM_OBJ_FILES_DIR)/libcuda/*.o \ $(SIM_OBJ_FILES_DIR)/cuda-sim/*.o \ $(SIM_OBJ_FILES_DIR)/cuda-sim/decuda_pred_table/*.o \ @@ -169,7 +169,6 @@ $(SIM_LIB_DIR)/libcudart.so: makedirs $(LIBS) cudalib if [ ! -f $(SIM_LIB_DIR)/libcudart.so.10.1 ]; then ln -s libcudart.so $(SIM_LIB_DIR)/libcudart.so.10.1; fi if [ ! -f $(SIM_LIB_DIR)/libcudart.so.11.0 ]; then ln -s libcudart.so $(SIM_LIB_DIR)/libcudart.so.11.0; fi - $(SIM_LIB_DIR)/libcudart.dylib: makedirs $(LIBS) cudalib g++ -dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,1.1,-current_version,1.1\ $(SIM_OBJ_FILES_DIR)/libcuda/*.o \ @@ -208,6 +207,12 @@ cuda-sim: makedirs $(MAKE) -C ./src/cuda-sim/ depend $(MAKE) -C ./src/cuda-sim/ +TFLAGS = -std=c++0x -I$(CUDA_INSTALL_PATH)/include +ifneq ($(DEBUG),1) + TFLAGS += -O3 +endif +TFLAGS += -g3 -fPIC + gpgpu-sim_uarch: makedirs cuda-sim $(MAKE) -C ./src/gpgpu-sim/ depend $(MAKE) -C ./src/gpgpu-sim/ @@ -3,20 +3,20 @@ processing units (GPUs) running GPU computing workloads written in CUDA or OpenCL. Also included in GPGPU-Sim is a performance visualization tool called AerialVision and a configurable and extensible energy model called GPUWattch. GPGPU-Sim and GPUWattch have been rigorously validated with performance and -power measurements of real hardware GPUs. +power measurements of real hardware GPUs. -This version of GPGPU-Sim has been tested with CUDA version 4.2, -5.0, 5.5, 6.0 and 7.5, 8.0, 9.0, 9.1 +This version of GPGPU-Sim has been tested with a subset of CUDA version 4.2, +5.0, 5.5, 6.0, 7.5, 8.0, 9.0, 9.1, 10, and 11 Please see the copyright notice in the file COPYRIGHT distributed with this release in the same directory as this file. -If you use GPGPU-Sim in your research, please cite: +If you use GPGPU-Sim 4.0 in your research, please cite: -Ali Bakhoda, George Yuan, Wilson W. L. Fung, Henry Wong, Tor M. Aamodt, -Analyzing CUDA Workloads Using a Detailed GPU Simulator, in IEEE International -Symposium on Performance Analysis of Systems and Software (ISPASS), Boston, MA, -April 19-21, 2009. +Mahmoud Khairy, Zhesheng Shen, Tor M. Aamodt, Timothy G Rogers. +Accel-Sim: An Extensible Simulation Framework for Validated GPU Modeling. +In proceedings of the 47th IEEE/ACM International Symposium on Computer Architecture (ISCA), +May 29 - June 3, 2020. If you use cuDNN and Pytorch support, the Checkpoint function or the Debigging tool for functional simulation error in GPGPU-Sim for your research, please cite: @@ -24,11 +24,6 @@ Jonathan Lew, Deval Shah, Suchita Pati, Shaylin Cattell, Mengchi Zhang, Amruth S Analyzing Machine Learning Workloads Using a Detailed GPU Simulator, arXiv:1811.08933, https://arxiv.org/abs/1811.08933 -If you use the memory system in GPGPU-Sim, or the Volta/Pascal models, -please cite: -Mahmoud Khairy, Jain Akshay, Tor Aamodt, Timothy G Rogers, -Exploring Modern GPU Memory System Design Challenges through Accurate Modeling, arXiv:1810.07269, -https://arxiv.org/abs/1810.07269 If you use the Tensor Core in GPGPU-Sim or CUTLASS Library for your research please cite: @@ -65,7 +60,7 @@ to the source code can be found here: <http://gpgpu-sim.org/gpuwattch/>. If you have questions, please sign up for the google groups page (see gpgpu-sim.org), but note that use of this simulator does not imply any level of -support. Questions answered on a best effort basis. +support. Questions answered on a best effort basis. To submit a bug report, go here: http://www.gpgpu-sim.org/bugs/ @@ -73,29 +68,28 @@ See Section 2 "INSTALLING, BUILDING and RUNNING GPGPU-Sim" below to get started. See file CHANGES for updates in this and earlier versions. +# CONTRIBUTIONS and HISTORY -1. CONTRIBUTIONS and HISTORY - -== GPGPU-Sim == +## GPGPU-Sim GPGPU-Sim was created by Tor Aamodt's research group at the University of -British Columbia. Many have directly contributed to development of GPGPU-Sim +British Columbia. Many have directly contributed to development of GPGPU-Sim including: Tor Aamodt, Wilson W.L. Fung, Ali Bakhoda, George Yuan, Ivan Sham, Henry Wong, Henry Tran, Andrew Turner, Aaron Ariel, Inderpret Singh, Tim Rogers, Jimmy Kwa, Andrew Boktor, Ayub Gubran Tayler Hetherington and others. GPGPU-Sim models the features of a modern graphics processor that are relevant -to non-graphics applications. The first version of GPGPU-Sim was used in a +to non-graphics applications. The first version of GPGPU-Sim was used in a MICRO'07 paper and follow-on ACM TACO paper on dynamic warp formation. That version of GPGPU-Sim used the SimpleScalar PISA instruction set for functional simulation, and various configuration files indicating which loops should be spawned as kernels on the GPU, along with reconvergence points required for -SIMT execution to provide a programming model simlar to CUDA/OpenCL. Creating +SIMT execution to provide a programming model simlar to CUDA/OpenCL. Creating benchmarks for the original GPGPU-Sim simulator was a very time consuming process and the validity of code generation for CPU run on a GPU was questioned -by some. These issues motivated the development an interface for directly +by some. These issues motivated the development an interface for directly running CUDA applications to leverage the growing number of applications being -developed to use CUDA. We subsequently added support for OpenCL and removed +developed to use CUDA. We subsequently added support for OpenCL and removed all SimpleScalar code. The interconnection network is simulated using the booksim simulator developed @@ -107,48 +101,49 @@ library (part of the CUDA toolkit). Code to interface with the CUDA Math library is contained in cuda-math.h, which also includes several structures derived from vector_types.h (one of the CUDA header files). -== GPUWattch Energy Model == +## GPUWattch Energy Model GPUWattch (introduced in GPGPU-Sim 3.2.0) was developed by researchers at the University of British Columbia, the University of Texas at Austin, and the -University of Wisconsin-Madison. Contributors to GPUWattch include Tor +University of Wisconsin-Madison. Contributors to GPUWattch include Tor Aamodt's research group at the University of British Columbia: Tayler Hetherington and Ahmed ElTantawy; Vijay Reddi's research group at the University of Texas at Austin: Jingwen Leng; and Nam Sung Kim's research group -at the University of Wisconsin-Madison: Syed Gilani. +at the University of Wisconsin-Madison: Syed Gilani. -GPUWattch leverages McPAT, which was developed by Sheng Li et al. at the +GPUWattch leverages McPAT, which was developed by Sheng Li et al. at the University of Notre Dame, Hewlett-Packard Labs, Seoul National University, and the University of California, San Diego. The paper can be found at -http://www.hpl.hp.com/research/mcpat/micro09.pdf. - - +http://www.hpl.hp.com/research/mcpat/micro09.pdf. -2. INSTALLING, BUILDING and RUNNING GPGPU-Sim +# INSTALLING, BUILDING and RUNNING GPGPU-Sim Assuming all dependencies required by GPGPU-Sim are installed on your system, to build GPGPU-Sim all you need to do is add the following line to your ~/.bashrc file (assuming the CUDA Toolkit was installed in /usr/local/cuda): - export CUDA_INSTALL_PATH=/usr/local/cuda +``` + export CUDA_INSTALL_PATH=/usr/local/cuda +``` then type - bash - source setup_environment - make +``` + bash + source setup_environment + make +``` -If the above fails, see "Step 1" and "Step 2" below. +If the above fails, see "Step 1" and "Step 2" below. If the above worked, see "Step 3" below, which explains how to run a CUDA benchmark on GPGPU-Sim. -Step 1: Dependencies -==================== +## Step 1: Dependencies -GPGPU-Sim was developed on SUSE Linux (this release was tested with SUSE +GPGPU-Sim was developed on SUSE Linux (this release was tested with SUSE version 11.3) and has been used on several other Linux platforms (both 32-bit -and 64-bit systems). In principle, GPGPU-Sim should work with any linux +and 64-bit systems). In principle, GPGPU-Sim should work with any linux distribution as long as the following software dependencies are satisfied. Download and install the CUDA Toolkit. It is recommended to use version 3.1 for @@ -159,35 +154,35 @@ install them in different directories and set your CUDA_INSTALL_PATH environment variable to point to the version you want to use. [Optional] If you want to run OpenCL on the simulator, download and install -NVIDIA's OpenCL driver from <http://developer.nvidia.com/opencl>. Update your +NVIDIA's OpenCL driver from <http://developer.nvidia.com/opencl>. Update your PATH and LD_LIBRARY_PATH as indicated by the NVIDIA install scripts. Note that -you will need to use the lib64 directory if you are using a 64-bit machine. We +you will need to use the lib64 directory if you are using a 64-bit machine. We have tested OpenCL on GPGPU-Sim using NVIDIA driver version 256.40 <http://developer.download.nvidia.com/compute/cuda/3_1/drivers/devdriver_3.1_linux_64_256.40.run> This version of GPGPU-Sim has been updated to support more recent versions of -the NVIDIA drivers (tested on version 295.20). +the NVIDIA drivers (tested on version 295.20). GPGPU-Sim dependencies: -* gcc -* g++ -* make -* makedepend -* xutils -* bison -* flex -* zlib -* CUDA Toolkit +- gcc +- g++ +- make +- makedepend +- xutils +- bison +- flex +- zlib +- CUDA Toolkit GPGPU-Sim documentation dependencies: -* doxygen -* graphvi +- doxygen +- graphvi AerialVision dependencies: -* python-pmw -* python-ply -* python-numpy -* libpng12-dev -* python-matplotlib +- python-pmw +- python-ply +- python-numpy +- libpng12-dev +- python-matplotlib We used gcc/g++ version 4.5.1, bison version 2.4.1, and flex version 2.5.35. @@ -195,113 +190,118 @@ If you are using Ubuntu, the following commands will install all required dependencies besides the CUDA Toolkit. GPGPU-Sim dependencies: -"sudo apt-get install build-essential xutils-dev bison zlib1g-dev flex -libglu1-mesa-dev" + + sudo apt-get install build-essential xutils-dev bison zlib1g-dev flex libglu1-mesa-dev GPGPU-Sim documentation dependencies: -"sudo apt-get install doxygen graphviz" + + sudo apt-get install doxygen graphviz AerialVision dependencies: -"sudo apt-get install python-pmw python-ply python-numpy libpng12-dev -python-matplotlib" + + sudo apt-get install python-pmw python-ply python-numpy libpng12-dev python-matplotlib CUDA SDK dependencies: -"sudo apt-get install libxi-dev libxmu-dev libglut3-dev" + + sudo apt-get install libxi-dev libxmu-dev libglut3-dev If you are running applications which use NVIDIA libraries such as cuDNN and cuBLAS, install them too. Finally, ensure CUDA_INSTALL_PATH is set to the location where you installed -the CUDA Toolkit (e.g., /usr/local/cuda) and that $CUDA_INSTALL_PATH/bin is in -your PATH. You probably want to modify your .bashrc file to incude the +the CUDA Toolkit (e.g., /usr/local/cuda) and that \$CUDA_INSTALL_PATH/bin is in +your PATH. You probably want to modify your .bashrc file to incude the following (this assumes the CUDA Toolkit was installed in /usr/local/cuda): export CUDA_INSTALL_PATH=/usr/local/cuda export PATH=$CUDA_INSTALL_PATH/bin If running applications which use cuDNN or cuBLAS: + export CUDNN_PATH=<Path To cuDNN Directory> export LD_LIBRARY_PATH=$CUDA_INSTALL_PATH/lib64:$CUDA_INSTALL_PATH/lib:$CUDNN_PATH/lib64 + -Step 2: Build -============= +## Step 2: Build To build the simulator, you first need to configure how you want it to be built. From the root directory of the simulator, type the following commands in a bash shell (you can check you are using a bash shell by running the command -"echo $SHELL", which should print "/bin/bash"): +"echo \$SHELL", which should print "/bin/bash"): source setup_environment <build_type> replace <build_type> with debug or release. Use release if you need faster simulation and debug if you need to run the simulator in gdb. If nothing is -specified, release will be used by default. +specified, release will be used by default. Now you are ready to build the simulator, just run -make + make + After make is done, the simulator would be ready to use. To clean the build, run -make clean + make clean To build the doxygen generated documentations, run -make docs + make docs -to clean the docs run +To clean the docs run + + make cleandocs -make cleandocs The documentation resides at doc/doxygen/html. -Step 3: Run -============ +To run Pytorch applications with the simulator, install the modified Pytorch library as well by following instructions [here](https://github.com/gpgpu-sim/pytorch-gpgpu-sim). +## Step 3: Run Before we run, we need to make sure the application's executable file is dynamically linked to CUDA runtime library. This can be done during compilation of your program by introducing the nvcc flag "--cudart shared" in makefile (quotes should be excluded). To confirm the same, type the follwoing command: -ldd <your_application_name> +`ldd <your_application_name>` -You should see that your application is using libcudart.so file in GPGPUSim directory. +You should see that your application is using libcudart.so file in GPGPUSim directory. If the application is a Pytorch application, `<your_application_name>` should be `$PYTORCH_BIN`, which should be set during the Pytorch installation. If running applications which use cuDNN or cuBLAS: - * Modify the Makefile or the compilation command of the application to change +* Modify the Makefile or the compilation command of the application to change all the dynamic links to static ones, for example: - * -L$(CUDA_PATH)/lib64 -lcublas to - -L$(CUDA_PATH)/lib64 -lcublas_static + * `-L$(CUDA_PATH)/lib64 -lcublas` to + `-L$(CUDA_PATH)/lib64 -lcublas_static` - * -L$(CUDNN_PATH)/lib64 -lcudnn to - -L$(CUDNN_PATH)/lib64 -lcudnn_static + * `-L$(CUDNN_PATH)/lib64 -lcudnn` to + `-L$(CUDNN_PATH)/lib64 -lcudnn_static` - * Modify the Makefile or the compilation command such that the following +* Modify the Makefile or the compilation command such that the following flags are used by the nvcc compiler: - -gencode arch=compute_61,code=compute_61 + `-gencode arch=compute_61,code=compute_61` (the number 61 refers to the SM version. You would need to set it based - on the GPGPU-Sim config "-gpgpu ptx force max capability" you use) + on the GPGPU-Sim config `-gpgpu-ptx-force-max-capability` you use) Copy the contents of configs/QuadroFX5800/ or configs/GTX480/ to your -application's working directory. These files configure the microarchitecture +application's working directory. These files configure the microarchitecture models to resemble the respective GPGPU architectures. To use ptxplus (native ISA) change the following options in the configuration file to "1" (Note: you need CUDA version 4.0) as follows: --gpgpu_ptx_use_cuobjdump 1 --gpgpu_ptx_convert_to_ptxplus 1 + -gpgpu_ptx_use_cuobjdump 1 + -gpgpu_ptx_convert_to_ptxplus 1 Now To run a CUDA application on the simulator, simply execute -source setup_environment <build_type> + source setup_environment <build_type> Use the same <build_type> you used while building the simulator. Then just launch the executable as you would if it was to run on the hardware. By -running "source setup_environment <build_type>" you change your LD_LIBRARY_PATH +running `source setup_environment <build_type>` you change your LD_LIBRARY_PATH to point to GPGPU-Sim's instead of CUDA or OpenCL runtime so that you do NOT need to re-compile your application simply to run it on GPGPU-Sim. @@ -310,12 +310,13 @@ LD_LIBRARY_PATH environment variable. The following GPGPU-Sim configuration options are used to enable GPUWattch - - power_simulation_enabled 1 (1=Enabled, 0=Not enabled) - - gpuwattch_xml_file <filename>.xml + -power_simulation_enabled 1 (1=Enabled, 0=Not enabled) + -gpuwattch_xml_file <filename>.xml + The GPUWattch XML configuration file name is set to gpuwattch.xml by default and -currently only supplied for GTX480 (default=gpuwattch_gtx480.xml). Please refer to -<http://gpgpu-sim.org/gpuwattch/> for more information. +currently only supplied for GTX480 (default=gpuwattch_gtx480.xml). Please refer to +<http://gpgpu-sim.org/gpuwattch/> for more information. Running OpenCL applications is identical to running CUDA applications. However, OpenCL applications need to communicate with the NVIDIA driver in order to @@ -332,11 +333,10 @@ samples then you will need to download, install and build the SDK. The CUDA applications from the ISPASS 2009 paper mentioned above are distributed separately on github under the repo ispass2009-benchmarks. -The README.ISPASS-2009 file distributed with the benchmarks now contains +The README.ISPASS-2009 file distributed with the benchmarks now contains updated instructions for running the benchmarks on GPGPU-Sim v3.x. - -3. (OPTIONAL) Updating GPGPU-Sim (ADVANCED USERS ONLY) +# (OPTIONAL) Contributing to GPGPU-Sim (ADVANCED USERS ONLY) If you have made modifications to the simulator and wish to incorporate new features/bugfixes from subsequent releases the following instructions may help. @@ -345,35 +345,41 @@ comfortable with using source control who have experience modifying and debugging GPGPU-Sim. WARNING: Before following the procedure below, back up your modifications to -GPGPU-Sim. The following procedure may cause you to lose all your changes. In +GPGPU-Sim. The following procedure may cause you to lose all your changes. In general, merging code changes can require manual intervention and even in the -case where a merge proceeds automatically it may introduce errors. If many -edits have been made the merge process can be a painful manual process. Hence, +case where a merge proceeds automatically it may introduce errors. If many +edits have been made the merge process can be a painful manual process. Hence, you will almost certainly want to have a copy of your code as it existed before -you followed the procedure below in case you need to start over again. You +you followed the procedure below in case you need to start over again. You will need to consult the documentation for git in addition to these instructions in the case of any complications. -STOP. BACK UP YOUR CHANGES BEFORE PROCEEDING. YOU HAVE BEEN WARNED. TWICE. +STOP. BACK UP YOUR CHANGES BEFORE PROCEEDING. YOU HAVE BEEN WARNED. TWICE. -To update GPGPU-Sim you need git to be installed on your system. Below we +To update GPGPU-Sim you need git to be installed on your system. Below we assume that you ran the following command to get the source code of GPGPU-Sim: -git clone git://dev.ece.ubc.ca/gpgpu-sim +``` + git clone git://dev.ece.ubc.ca/gpgpu-sim +``` Since running the above command you have made local changes and we have published changes to GPGPU-Sim on the above git server. You have looked at the changes we made, looking at both the new CHANGES file and probably even the -source code differences. You decide you want to incorporate our changes into -your modified version of GPGPU-Sim. +source code differences. You decide you want to incorporate our changes into +your modified version of GPGPU-Sim. Before updating your source code, we recommend you remove any object files: -make clean +``` + make clean +``` Then, run the following command in the root directory of GPGPU-Sim: -git pull +``` + git pull +``` While git is pulling the latest changes, conflicts might arise due to changes that you made that conflict with the latest updates. In this case, you need to @@ -381,40 +387,42 @@ resolved those conflicts manually. You can either edit the conflicting files directly using your favorite text editor, or you can use the following command to open a graphical merge tool to do the merge: -git mergetool +``` + git mergetool +``` -3.1 Testing updated version of GPGPU-Sim +## Testing updated version of GPGPU-Sim -Now you should test that the merged version "works". This means following the -steps for building GPGPU-Sim in the *new* README file (not this version) since +Now you should test that the merged version "works". This means following the +steps for building GPGPU-Sim in the _new_ README file (not this version) since they may have changed. Assuming the code compiles without errors/warnings the -next step is to do some regression testing. At UBC we have an extensive set of +next step is to do some regression testing. At UBC we have an extensive set of regression tests we run against our internal development branch when we make -changes. In the future we may make this set of regression tests publically +changes. In the future we may make this set of regression tests publically available. For now, you will want to compile the merged code and re-run all of the applications you care about (implying these applications worked for you before you did the merge). You want to do this before making further changes to identify any compile time or runtime errors that occur due to the code merging -process. +process. -4. MISCELLANEOUS +# MISCELLANEOUS -4.1 Speeding up the execution +## Speeding up the execution Some applications take several hours to execute on GPGPUSim. This is because the simulator has to dump the PTX, analyze them and get resource usage statistics. This can be avoided everytime we execute the program in the following way: -Step 1: Execute the program by enabling “-save_embedded_ptx 1” in config file, execute the code and let cuobjdump command dump all necessary files. After this process, you will get 2 new files namely: _cuobjdump_complete_output_<some_random_name> and _1.ptx +1. Execute the program by enabling “-save_embedded_ptx 1” in config file, execute the code and let cuobjdump command dump all necessary files. After this process, you will get 2 new files namely: _cuobjdump_complete_output_<some_random_name> and _1.ptx -Step 2: Create new environment variables or include the below in your .bashrc file: - a. export PTX_SIM_USE_PTX_FILE=_1.ptx - b. export PTX_SIM_KERNELFILE=_1.ptx - c. export CUOBJDUMP_SIM_FILE=_cuobjdump_complete_output_<some_random_name> +2. Create new environment variables or include the below in your .bashrc file: + 1. export PTX_SIM_USE_PTX_FILE=_1.ptx + 2. export PTX_SIM_KERNELFILE=_1.ptx + 3. export CUOBJDUMP_SIM_FILE=_cuobjdump_complete_output_<some_random_name> -Step 3: Disable -save_embedded_ptx flag, execute the code again. This will skip the dumping by cuobjdump and directly goes to executing the program thus saving time. +3. Disable -save_embedded_ptx flag, execute the code again. This will skip the dumping by cuobjdump and directly goes to executing the program thus saving time. -4.2 Debugging failing GPGPU-Sim Regressions +## Debugging failing GPGPU-Sim Regressions Credits: Tor M Aamodt @@ -428,55 +436,60 @@ To debug failing GPGPU-Sim regression tests you need to run them locally. The f 3. Run the following command (this is all one line) to run the regressions in docker: + ``` + docker run --privileged -v `pwd`:/home/runner/gpgpu-sim_distribution:rw aamodt/gpgpu-sim_regress:latest /bin/bash -c "./start_torque.sh; chown -R runner /home/runner/gpgpu-sim_distribution; su - runner -c 'source /home/runner/gpgpu-sim_distribution/setup_environment && make -j -C /home/runner/gpgpu-sim_distribution && cd /home/runner/gpgpu-sim_simulations/ && git pull && /home/runner/gpgpu-sim_simulations/util/job_launching/run_simulations.py -c /home/runner/gpgpu-sim_simulations/util/job_launching/regression_recipies/rodinia_2.0-ft/configs.gtx1080ti.yml -N regress && /home/runner/gpgpu-sim_simulations/util/job_launching/monitor_func_test.py -v -N regress'; tail -f /dev/null" + ``` + Explanation: The last part of this command, "tail -f /dev/null" will keep the docker container running after the regressions finish. This enables you to log into the container to run the same tests inside gdb so you can debug. The "--privileged" part enables you to use breakpoints inside gdb in a container. The "-v" part maps the current directory (with the GPGPU-Sim source code you want to test) into the container. The string "aamodt/gpgpu-sim_regress:latest" is a tag for a container setup to run regressions which will be downloaded from docker hub. The portion starting with /bin/bash is a set of commands run inside a bash shell inside the container. E.g., the command start_torque.sh starts up a queue manager inside the container. - docker run --privileged -v `pwd`:/home/runner/gpgpu-sim_distribution:rw aamodt/gpgpu-sim_regress:latest /bin/bash -c "./start_torque.sh; chown -R runner /home/runner/gpgpu-sim_distribution; su - runner -c 'source /home/runner/gpgpu-sim_distribution/setup_environment && make -j -C /home/runner/gpgpu-sim_distribution && cd /home/runner/gpgpu-sim_simulations/ && git pull && /home/runner/gpgpu-sim_simulations/util/job_launching/run_simulations.py -c /home/runner/gpgpu-sim_simulations/util/job_launching/regression_recipies/rodinia_2.0-ft/configs.gtx1080ti.yml -N regress && /home/runner/gpgpu-sim_simulations/util/job_launching/monitor_func_test.py -v -N regress’; tail -f /dev/null" - -Explanation: The last part of this command, "tail -f /dev/null" will keep the docker container running after the regressions finish. This enables you to log into the container to run the same tests inside gdb so you can debug. The "--privileged" part enables you to use breakpoints inside gdb in a container. The "-v" part maps the current directory (with the GPGPU-Sim source code you want to test) into the container. The string "aamodt/gpgpu-sim_regress:latest" is a tag for a container setup to run regressions which will be downloaded from docker hub. The portion starting with /bin/bash is a set of commands run inside a bash shell inside the container. E.g., the command start_torque.sh starts up a queue manager inside the container. - -If the above command stops with the message "fatal: unable to access 'https://github.com/tgrogers/gpgpu-sim_simulations.git/': Could not resolve host: github.com" this likely means your computer sits behind a firewall which is blocking access to Google's name servers (e.g., 8.8.8.8). To get around this you will need to modify th above command to point to your local DNS server. Lookup your DNS server IP address which we will call <DNS_IP_ADDRESS> below. On Ubuntu run "ifconfig" to lookup the network interface connecting your computer to the network. Then run "nmcli device show <interface name>" to find the IP address of your DNS server. Modify the above command to include "--dns <DNS_IP_ADDRESS>" after "run", E.g., - - docker run --dns <DNS_IP_ADDRESS> --privileged -v `pwd`:/home/runner/gpgpu-sim_distribution:rw aamodt/gpgpu-sim_regress:latest /bin/bash -c "./start_torque.sh; chown -R runner /home/runner/gpgpu-sim_distribution; su - runner -c 'source /home/runner/gpgpu-sim_distribution/setup_environment && make -j -C /home/runner/gpgpu-sim_distribution && cd /home/runner/gpgpu-sim_simulations/ && git pull && /home/runner/gpgpu-sim_simulations/util/job_launching/run_simulations.py -c /home/runner/gpgpu-sim_simulations/util/job_launching/regression_recipies/rodinia_2.0-ft/configs.gtx1080ti.yml -N regress && /home/runner/gpgpu-sim_simulations/util/job_launching/monitor_func_test.py -v -N regress’; tail -f /dev/null" + If the above command stops with the message "fatal: unable to access 'https://github.com/tgrogers/gpgpu-sim_simulations.git/': Could not resolve host: github.com" this likely means your computer sits behind a firewall which is blocking access to Google's name servers (e.g., 8.8.8.8). To get around this you will need to modify th above command to point to your local DNS server. Lookup your DNS server IP address which we will call <DNS_IP_ADDRESS> below. On Ubuntu run "ifconfig" to lookup the network interface connecting your computer to the network. Then run "nmcli device show <interface name>" to find the IP address of your DNS server. Modify the above command to include "--dns <DNS_IP_ADDRESS>" after "run", E.g., + ``` + docker run --dns <DNS_IP_ADDRESS> --privileged -v `pwd`:/home/runner/gpgpu-sim_distribution:rw aamodt/gpgpu-sim_regress:latest /bin/bash -c "./start_torque.sh; chown -R runner /home/runner/gpgpu-sim_distribution; su - runner -c 'source /home/runner/gpgpu-sim_distribution/setup_environment && make -j -C /home/runner/gpgpu-sim_distribution && cd /home/runner/gpgpu-sim_simulations/ && git pull && /home/runner/gpgpu-sim_simulations/util/job_launching/run_simulations.py -c /home/runner/gpgpu-sim_simulations/util/job_launching/regression_recipies/rodinia_2.0-ft/configs.gtx1080ti.yml -N regress && /home/runner/gpgpu-sim_simulations/util/job_launching/monitor_func_test.py -v -N regress'; tail -f /dev/null" + ``` 4. Find the CONTAINER ID associated with your docker container by running "docker ps". 5. Log into the container by running the command: - - docker exec -it <CONTAINER_ID> /bin/bash -c "su -l runner" - -The container is running Ubuntu 16.04 and has screen, cscope and vim installed (if you find a favorite Linux tool missing, it is fairly easy to create derived containers that have additional tools). + ``` + docker exec -it <CONTAINER_ID> /bin/bash -c "su -l runner"` + ``` + The container is running Ubuntu 16.04 and has screen, cscope and vim installed (if you find a favorite Linux tool missing, it is fairly easy to create derived containers that have additional tools). 6. Lookup the directory of the regression test you want to debug by going to the regression log file directory: - + ``` cd /home/runner/gpgpu-sim_simulations/util/job_launching/logfiles + ``` 7. The file "failed_job_log_sim_log.regress.<DATE>.txt" includes information about the failed test including its simulation directory. For the following example, I'll assume the first failing test was "hotspot-rodinia-2.0-ft-30_6_40___data_result_30_6_40_txt--GTX1080Ti" for which the simulation directory is /home/runner/gpgpu-sim_simulations/util/job_launching/../../sim_run_4.2/hotspot-rodinia-2.0-ft/30_6_40___data_result_30_6_40_txt/GTX1080Ti/ 8. Change to the simulation directory using: - + ``` cd <simulation_directory> + ``` + E.g., `cd /home/runner/gpgpu-sim_simulations/util/job_launching/../../sim_run_4.2/hotspot-rodinia-2.0-ft/30_6_40___data_result_30_6_40_txt/GTX1080Ti/` -E.g., "cd /home/runner/gpgpu-sim_simulations/util/job_launching/../../sim_run_4.2/hotspot-rodinia-2.0-ft/30_6_40___data_result_30_6_40_txt/GTX1080Ti/" - -This directory should contain a file called "torque.sim" that contains commands used to launch the simulation during regression tests. We will modify this file to enable us to re-run the regression test in gdb. This directory should also contain a file containing the standard output during the regression test. This file will end in .o<number> where <number> is the torque queue manager job number. For the running example for me this file is called "hotspot-rodinia-2.0-ft-30_6_40___data_result_30_6_40_txt.o2". Open this file to determine the LD_LIBRARY_PATH settings used when launching the simulation. Look for a line that starts "doing: export LD_LIBRARY_PATH" and copy the entire line starting with "export LD_LIBRARY_PATH ..." + This directory should contain a file called "torque.sim" that contains commands used to launch the simulation during regression tests. We will modify this file to enable us to re-run the regression test in gdb. This directory should also contain a file containing the standard output during the regression test. This file will end in .o<number> where <number> is the torque queue manager job number. For the running example for me this file is called "hotspot-rodinia-2.0-ft-30_6_40___data_result_30_6_40_txt.o2". Open this file to determine the LD_LIBRARY_PATH settings used when launching the simulation. Look for a line that starts "doing: export LD_LIBRARY_PATH" and copy the entire line starting with "export LD_LIBRARY_PATH ..." 9. Paste the "export LD_LIBRARY_PATH ..." line into the bash shell to set LD_LIBRARY_PATH. E.g., - + ``` export LD_LIBRARY_PATH=/home/runner/gpgpu-sim_simulations/util/job_launching/../../sim_run_4.2/gpgpu-sim-builds/libcudart_gpgpu-sim_git-commit-177d02254ae38b6331b17dd6cd139b570a03c589_modified_0.so:/gpgpu-sim/usr/local/gcc-4.5.4/lib64:/gpgpu-sim/usr/local/gcc-4.5.4/lib:/gpgpu-sim/usr/local/gcc-4.5.4/lib/gcc/x86_64-unknown-linux-gnu/lib64/:/gpgpu-sim/usr/local/gcc-4.5.4/lib/gcc/x86_64-unknown-linux-gnu/4.5.4/:/usr/lib/x86_64-linux-gnu:/home/runner/gpgpu-sim_distribution/lib/gcc-4.5.4/cuda-4020/release:/gpgpu-sim/usr/local/gcc-4.5.4/lib64:/gpgpu-sim/usr/local/gcc-4.5.4/lib:/gpgpu-sim/usr/local/gcc-4.5.4/lib/gcc/x86_64-unknown-linux-gnu/lib64/:/gpgpu-sim/usr/local/gcc-4.5.4/lib/gcc/x86_64-unknown-linux-gnu/4.5.4/:/usr/lib/x86_64-linux-gnu: + ``` 10. In the same shell, build the debug version of GPGPU-Sim then return to the directory above: - + ``` pushd ~/gpgpu-sim_distribution/ source setup_environment debug make popd + ``` 11. Open and edit torque.sim and preface the very last line with "gdb --args ". After editing the last line in torque.sim should look something like: - + ``` gdb --args /home/runner/gpgpu-sim_simulations/util/job_launching/../../benchmarks/bin/4.2/release/hotspot-rodinia-2.0-ft 30 6 40 ./data/result_30_6_40.txt + ``` 12. Re-run the regression test in gdb by sourcing the torque.sim file: - + ``` . torque.sim - -This will put you in at the (gdb) prompt. Setup any breakpoints needed and run. + ``` + This will put you in at the (gdb) prompt. Setup any breakpoints needed and run. diff --git a/aerialvision/guiclasses.py b/aerialvision/guiclasses.py index 45fed26..04036a8 100644 --- a/aerialvision/guiclasses.py +++ b/aerialvision/guiclasses.py @@ -1365,7 +1365,8 @@ class graphManager: interpolation = 'nearest' norm = plotFormat.norm im = self.plot.imshow(y, cmap = cmap, interpolation = interpolation, aspect = 'auto', norm = norm ) - tmp = im.get_axes().get_position().get_points() + # tmp = im.get_axes().get_position().get_points() + tmp = im.get_window_extent().get_points() if (plotID in self.cbarAxes): self.figure.delaxes(self.cbarAxes[plotID]) diff --git a/configs/tested-cfgs/SM2_GTX480/gpgpusim.config b/configs/tested-cfgs/SM2_GTX480/gpgpusim.config index 6f088ea..609a9ef 100644 --- a/configs/tested-cfgs/SM2_GTX480/gpgpusim.config +++ b/configs/tested-cfgs/SM2_GTX480/gpgpusim.config @@ -63,10 +63,10 @@ -gpgpu_shmem_size 49152 -gpgpu_shmem_sizeDefault 49152 -icnt_flit_size 40 --gmem_skip_L1D 0 +-gpgpu_gmem_skip_L1D 0 -gpgpu_n_cluster_ejection_buffer_size 32 --l1_latency 35 --smem_latency 26 +-gpgpu_l1_latency 35 +-gpgpu_smem_latency 26 -gpgpu_flush_l1_cache 1 # The alternative configuration for fermi in case cudaFuncCachePreferL1 is selected @@ -77,8 +77,8 @@ -gpgpu_cache:dl2 S:64:128:8,L:B:m:L:L,A:256:4,4:0,32 -gpgpu_cache:dl2_texture_only 0 -gpgpu_dram_partition_queues 64:64:64:64 --perf_sim_memcpy 1 --memory_partition_indexing 0 +-gpgpu_perf_sim_memcpy 1 +-gpgpu_memory_partition_indexing 0 -gpgpu_cache:il1 N:4:128:4,L:R:f:N:L,S:2:32,4 -gpgpu_tex_cache:l1 N:4:128:24,L:R:m:N:L,T:128:4,128:2 @@ -104,7 +104,7 @@ -inter_config_file config_fermi_islip.icnt # memory partition latency config --rop_latency 120 +-gpgpu_l2_rop_latency 120 -dram_latency 100 # dram model config diff --git a/configs/tested-cfgs/SM3_KEPLER_TITAN/config_kepler_islip.icnt b/configs/tested-cfgs/SM3_KEPLER_TITAN/config_kepler_islip.icnt new file mode 100644 index 0000000..2fe3b53 --- /dev/null +++ b/configs/tested-cfgs/SM3_KEPLER_TITAN/config_kepler_islip.icnt @@ -0,0 +1,73 @@ +//21*1 fly with 32 flits per packet under gpgpusim injection mode +use_map = 0; +flit_size = 40; + +// currently we do not use this, see subnets below +network_count = 2; + +// Topology +topology = fly; +k = 38; +n = 1; + +// Routing + +routing_function = dest_tag; + +// Flow control + +num_vcs = 1; +vc_buf_size = 64; +input_buffer_size = 256; +ejection_buffer_size = 64; +boundary_buffer_size = 64; + +wait_for_tail_credit = 0; + +// Router architecture + +vc_allocator = islip; //separable_input_first; +sw_allocator = islip; //separable_input_first; +alloc_iters = 1; + +credit_delay = 0; +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; + +input_speedup = 1; +output_speedup = 1; +internal_speedup = 2.0; + +// Traffic, GPGPU-Sim does not use this + +traffic = uniform; +packet_size ={{1,2,3,4},{10,20}}; +packet_size_rate={{1,1,1,1},{2,1}}; + +// Simulation - Don't change + +sim_type = gpgpusim; +//sim_type = latency; +injection_rate = 0.1; + +subnets = 2; + +// Always use read and write no matter following line +//use_read_write = 1; + + +read_request_subnet = 0; +read_reply_subnet = 1; +write_request_subnet = 0; +write_reply_subnet = 1; + +read_request_begin_vc = 0; +read_request_end_vc = 0; +write_request_begin_vc = 0; +write_request_end_vc = 0; +read_reply_begin_vc = 0; +read_reply_end_vc = 0; +write_reply_begin_vc = 0; +write_reply_end_vc = 0; + diff --git a/configs/tested-cfgs/SM3_KEPLER_TITAN/gpgpusim.config b/configs/tested-cfgs/SM3_KEPLER_TITAN/gpgpusim.config new file mode 100644 index 0000000..c83159f --- /dev/null +++ b/configs/tested-cfgs/SM3_KEPLER_TITAN/gpgpusim.config @@ -0,0 +1,183 @@ +# This config models the KEPLER (TITAN) +# For more info about this card, see Nvidia White paper +# https://wr0.wr.inf.h-brs.de/wr/hardware/nodes3/nvidia/NVIDIA-Kepler-GK110-Architecture-Whitepaper.pdf + +# functional simulator specification +-gpgpu_ptx_instruction_classification 0 +-gpgpu_ptx_sim_mode 0 +-gpgpu_ptx_force_max_capability 35 +-gpgpu_ignore_resources_limitation 1 + +# Device Limits +-gpgpu_stack_size_limit 1024 +-gpgpu_heap_size_limit 8388608 +-gpgpu_runtime_sync_depth_limit 2 +-gpgpu_runtime_pending_launch_count_limit 2048 + +# Compute Capability +-gpgpu_compute_capability_major 3 +-gpgpu_compute_capability_minor 5 + +# PTX execution-driven +-gpgpu_ptx_convert_to_ptxplus 0 +-gpgpu_ptx_save_converted_ptxplus 0 +# SASS trace-driven mode execution +#-trace_driven_mode 1 + +# high level architecture configuration +-gpgpu_n_clusters 14 +-gpgpu_n_cores_per_cluster 1 +-gpgpu_n_mem 12 +-gpgpu_n_sub_partition_per_mchannel 2 + +# Kepler clock domains +#-gpgpu_clock_domains <Core Clock>:<Interconnect Clock>:<L2 Clock>:<DRAM Clock> +# Kepler NVIDIA TITAN clock domains are adopted from +# https://en.wikipedia.org/wiki/GeForce_700_series +-gpgpu_clock_domains 837.0:837.0:837.0:1502.0 + +# shader core pipeline config +-gpgpu_shader_registers 65536 +-gpgpu_occupancy_sm_number 62 + +# This implies a maximum of 64 warps/SM +-gpgpu_shader_core_pipeline 2048:32 +-gpgpu_shader_cta 16 +-gpgpu_simd_model 1 + +# Pipeline widths and number of FUs +# ID_OC_SP,ID_OC_DP,ID_OC_INT,ID_OC_SFU,ID_OC_MEM,OC_EX_SP,OC_EX_DP,OC_EX_INT,OC_EX_SFU,OC_EX_MEM,EX_WB +## Kepler has 6 SP SIMD units, 4 DPs and 2 SFU units per SM. +# There is no INT unit in kepler +-gpgpu_pipeline_widths 6,4,0,2,1,6,4,0,2,1,12 +-gpgpu_num_sp_units 6 +-gpgpu_num_sfu_units 2 +-gpgpu_num_dp_units 4 + +# Instruction latencies and initiation intervals +# "ADD,MAX,MUL,MAD,DIV" +# All Div operations are executed on SFU unit +# Throughput (initiation latency) are adopted from CUDA SDK document V8, section 5.4.1, Table 2 +-ptx_opcode_latency_int 4,13,4,5,145,32 +-ptx_opcode_initiation_int 1,1,1,1,4,4 +-ptx_opcode_latency_fp 4,13,4,5,39 +-ptx_opcode_initiation_fp 1,2,1,1,4 +-ptx_opcode_latency_dp 8,19,8,8,330 +-ptx_opcode_initiation_dp 2,8,8,8,130 +-ptx_opcode_initiation_sfu 2 +-ptx_opcode_latency_sfu 200 + +# enable operand collector +-gpgpu_operand_collector_num_units_sp 12 +-gpgpu_operand_collector_num_units_sfu 6 +-gpgpu_operand_collector_num_units_mem 8 +-gpgpu_operand_collector_num_units_dp 6 +-gpgpu_operand_collector_num_in_ports_sp 2 +-gpgpu_operand_collector_num_out_ports_sp 2 +-gpgpu_operand_collector_num_in_ports_sfu 2 +-gpgpu_operand_collector_num_out_ports_sfu 2 +-gpgpu_operand_collector_num_in_ports_mem 1 +-gpgpu_operand_collector_num_out_ports_mem 1 +-gpgpu_operand_collector_num_in_ports_dp 1 +-gpgpu_operand_collector_num_out_ports_dp 1 +-gpgpu_num_reg_banks 16 +-gpgpu_reg_file_port_throughput 2 + +# shared memory bankconflict detection +-gpgpu_shmem_num_banks 32 +-gpgpu_shmem_limited_broadcast 0 +-gpgpu_shmem_warp_parts 1 +# Use kepler Coalsce arhitetecture +-gpgpu_coalesce_arch 35 + +## In Kepler, a warp scheduler can issue 2 insts per cycle +-gpgpu_max_insn_issue_per_warp 2 +-gpgpu_dual_issue_diff_exec_units 0 + +# Kepler TITAN has four schedulers per core +-gpgpu_num_sched_per_core 4 +# Greedy then oldest scheduler +-gpgpu_scheduler gto + +# <nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>:<set_index_fn>,<mshr>:<N>:<merge>,<mq>:**<fifo_entry> +# ** Optional parameter - Required when mshr_type==Texture Fifo +# Note: Hashing set index function (H) only applies to a set size of 32 or 64. +# The defulat is to disable the L1 cache, unless cache modifieres are used +-gpgpu_cache:dl1 S:4:128:32,L:L:s:N:L,A:256:8,16:0,32 +-gpgpu_cache:dl1PrefL1 S:4:128:96,L:L:s:N:L,A:256:8,16:0,32 +-gpgpu_cache:dl1PrefShared S:4:128:32,L:L:s:N:L,A:256:8,16:0,32 +-gpgpu_shmem_size 49152 +-gpgpu_shmem_sizeDefault 49152 +-gpgpu_shmem_size_PrefL1 16384 +-gpgpu_shmem_size_PrefShared 49152 +# By default, L1 cache is disabled in Kepler P102 and only enabled for local memory +# requests with .nc modifier or __ldg mehtod will be cached in L1 cache even with gmem_skip_L1D=1 +-gpgpu_gmem_skip_L1D 1 +-icnt_flit_size 40 +-gpgpu_n_cluster_ejection_buffer_size 32 +-gpgpu_l1_latency 82 +-smem_latency 24 +-gpgpu_flush_l1_cache 1 + +# 32 sets, each 128 bytes 16-way for each memory sub partition (128 KB per memory sub partition). This gives 1.5MB L2 cache +-gpgpu_cache:dl2 S:32:128:16,L:B:m:L:P,A:256:64,16:0,32 +-gpgpu_cache:dl2_texture_only 0 +-gpgpu_dram_partition_queues 32:32:32:32 +-gpgpu_perf_sim_memcpy 1 +-gpgpu_memory_partition_indexing 0 + +# 4 KB Inst. +-gpgpu_cache:il1 N:8:128:4,L:R:f:N:L,S:2:48,4 +-gpgpu_inst_fetch_throughput 8 +# 48 KB Tex +-gpgpu_tex_cache:l1 N:16:128:24,L:R:m:N:L,T:128:4,128:2 +# 12 KB Const +-gpgpu_const_cache:l1 N:128:64:2,L:R:f:N:L,S:2:64,4 + +# interconnection +-network_mode 1 +-inter_config_file config_kepler_islip.icnt + +# memory partition latency config +-gpgpu_l2_rop_latency 120 +-dram_latency 100 + +# dram model config +-gpgpu_dram_scheduler 1 +-gpgpu_frfcfs_dram_sched_queue_size 64 +-gpgpu_dram_return_queue_size 64 + +# for NVIDIA TITAN, bus width is 384bits (12 DRAM chips x 32 bits) +# 12 memory paritions, 4 bytes (1 DRAM chip) per memory partition +# the atom size of GDDR5X (the smallest read request) is 32 bytes +-gpgpu_n_mem_per_ctrlr 1 +-gpgpu_dram_buswidth 4 +-gpgpu_dram_burst_length 8 +-dram_data_command_freq_ratio 4 # GDDR5X is QDR +-gpgpu_mem_address_mask 1 +-gpgpu_mem_addr_mapping dramid@8;00000000.00000000.00000000.00000000.0000RRRR.RRRRRRRR.RBBBCCCC.BCCSSSSS + +# Use the same GDDR5 timing, scaled to 2500MHZ +-gpgpu_dram_timing_opt "nbk=16:CCD=2:RRD=8:RCD=16:RAS=37:RP=16:RC=52: + CL=16:WL=6:CDLR=7:WR=16:nbkgrp=4:CCDL=4:RTPL=3" + +-dram_bnk_indexing_policy 0 +-dram_bnkgrp_indexing_policy 1 + +#-dram_seperate_write_queue_enable 1 +#-dram_write_queue_size 64:56:32 + +# stat collection +-gpgpu_memlatency_stat 14 +-gpgpu_runtime_stat 500 +-enable_ptx_file_line_stats 1 +-visualizer_enabled 0 + +# power model configs, disable it untill we create a real energy model for Kepler +-power_simulation_enabled 0 + +# tracing functionality +#-trace_enabled 1 +#-trace_components WARP_SCHEDULER,SCOREBOARD +#-trace_sampling_core 0 + diff --git a/configs/tested-cfgs/SM6_TITANX/gpgpusim.config b/configs/tested-cfgs/SM6_TITANX/gpgpusim.config index 391269e..5b243a5 100644 --- a/configs/tested-cfgs/SM6_TITANX/gpgpusim.config +++ b/configs/tested-cfgs/SM6_TITANX/gpgpusim.config @@ -13,6 +13,7 @@ -gpgpu_heap_size_limit 8388608 -gpgpu_runtime_sync_depth_limit 2 -gpgpu_runtime_pending_launch_count_limit 2048 +-gpgpu_kernel_launch_latency 5000 # Compute Capability -gpgpu_compute_capability_major 6 @@ -23,9 +24,8 @@ -gpgpu_ptx_save_converted_ptxplus 0 # high level architecture configuration -# P102 has two semi-indp scheds per core, and two cores per cluster -gpgpu_n_clusters 28 --gpgpu_n_cores_per_cluster 2 +-gpgpu_n_cores_per_cluster 1 -gpgpu_n_mem 12 -gpgpu_n_sub_partition_per_mchannel 2 @@ -36,110 +36,107 @@ -gpgpu_clock_domains 1417.0:1417.0:1417.0:2500.0 # shader core pipeline config --gpgpu_shader_registers 32768 +-gpgpu_shader_registers 65536 -gpgpu_occupancy_sm_number 62 # This implies a maximum of 32 warps/SM --gpgpu_shader_core_pipeline 1024:32 --gpgpu_shader_cta 16 +-gpgpu_shader_core_pipeline 2048:32 +-gpgpu_shader_cta 32 -gpgpu_simd_model 1 # Pipeline widths and number of FUs # ID_OC_SP,ID_OC_DP,ID_OC_INT,ID_OC_SFU,ID_OC_MEM,OC_EX_SP,OC_EX_DP,OC_EX_INT,OC_EX_SFU,OC_EX_MEM,EX_WB -## Pascal GP102 has 4 SP SIMD units and 4 SFU units per SM. In this config, we split SM into two shader cores, each has 2 SPs and 2 SFUs -# There is no int unit in Pascal -## we need to scale the number of pipeline registers to be equal to the number of SP units --gpgpu_pipeline_widths 2,1,0,2,1,2,1,0,2,1,5 --gpgpu_num_sp_units 2 --gpgpu_num_sfu_units 2 --gpgpu_num_dp_units 1 - +## Pascal GP102 has 4 SP SIMD units and 4 SFU units per SM. +# There is no INT unit in Pascal +-gpgpu_pipeline_widths 4,0,0,4,4,4,0,0,4,4,8 +-gpgpu_num_sp_units 4 +-gpgpu_num_sfu_units 4 # Instruction latencies and initiation intervals # "ADD,MAX,MUL,MAD,DIV,SHFL" # All Div operations are executed on SFU unit -# Throughput (initiation latency) are adopted from CUDA SDK document V8, section 5.4.1, Table 2 -ptx_opcode_latency_int 4,13,4,5,145,32 -ptx_opcode_initiation_int 1,1,1,1,4,4 --ptx_opcode_latency_fp 4,13,4,5,39 +-ptx_opcode_latency_fp 4,13,4,4,39 -ptx_opcode_initiation_fp 1,2,1,1,4 -ptx_opcode_latency_dp 8,19,8,8,330 -ptx_opcode_initiation_dp 8,8,8,8,130 -ptx_opcode_initiation_sfu 4 --ptx_opcode_latency_sfu 8 +-ptx_opcode_latency_sfu 20 + +# in sub_core_model, schedulers are isolated, each scheduler has its own register file and EUs +-gpgpu_sub_core_model 1 +# enable operand collector +# disable specialized operand collectors and use generic operand collectors instead +-gpgpu_enable_specialized_operand_collector 0 +-gpgpu_operand_collector_num_units_gen 8 +-gpgpu_operand_collector_num_in_ports_gen 8 +-gpgpu_operand_collector_num_out_ports_gen 8 +# 16 register banks, 4 banks per subcore +-gpgpu_num_reg_banks 16 +-gpgpu_reg_file_port_throughput 2 +# shared memory bankconflict detection +-gpgpu_shmem_num_banks 32 +-gpgpu_shmem_limited_broadcast 0 +-gpgpu_shmem_warp_parts 1 +# Use Pascal Coalsce arhitetecture +-gpgpu_coalesce_arch 61 + +# Pascal 102 has four schedulers per core +-gpgpu_num_sched_per_core 4 +# Greedy then oldest scheduler +-gpgpu_scheduler gto + +## In Pascal, a warp scheduler can issue 2 insts per cycle using 2 diff execution units +-gpgpu_max_insn_issue_per_warp 2 +-gpgpu_dual_issue_diff_exec_units 1 -# latencies and cache configs are adopted from: -# https://arxiv.org/pdf/1804.06826.pdf +## L1/shared memory configuration # <nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>:<set_index_fn>,<mshr>:<N>:<merge>,<mq>:**<fifo_entry> # ** Optional parameter - Required when mshr_type==Texture Fifo # Note: Hashing set index function (H) only applies to a set size of 32 or 64. -# Pascal GP102 has 96KB Shared memory divided over 2 cores, each has 48KB -# Pascal GP102 has 2 banks L1 cache, where each is 24KB L1 cache # The defulat is to disable the L1 cache, unless cache modifieres are used --gpgpu_cache:dl1 S:4:128:48,L:L:s:N:L,A:256:8,16:0,32 --gpgpu_cache:dl1PrefL1 S:4:128:48,L:L:s:N:L,A:256:8,16:0,32 --gpgpu_cache:dl1PrefShared S:4:128:48,L:L:s:N:L,A:256:8,16:0,32 --gpgpu_shmem_size 49152 --gpgpu_shmem_sizeDefault 49152 --gpgpu_shmem_size_PrefL1 49152 --gpgpu_shmem_size_PrefShared 49152 +-gpgpu_l1_banks 2 +-gpgpu_cache:dl1 S:4:128:96,L:L:s:N:L,A:256:8,16:0,32 +-gpgpu_cache:dl1PrefL1 S:4:128:96,L:L:s:N:L,A:256:8,16:0,32 +-gpgpu_cache:dl1PrefShared S:4:128:96,L:L:s:N:L,A:256:8,16:0,32 +-gpgpu_shmem_size 98304 +-gpgpu_shmem_sizeDefault 98304 +-gpgpu_shmem_size_PrefL1 98304 +-gpgpu_shmem_size_PrefShared 98304 # By default, L1 cache is disabled in Pascal P102. # requests with .nc modifier or __ldg mehtod will be cached in L1 cache even with gmem_skip_L1D=1 --gmem_skip_L1D 1 +-gpgpu_gmem_skip_L1D 1 -icnt_flit_size 40 -gpgpu_n_cluster_ejection_buffer_size 32 --l1_latency 82 --smem_latency 24 +-gpgpu_l1_latency 82 +-gpgpu_smem_latency 24 -gpgpu_flush_l1_cache 1 # 64 sets, each 128 bytes 16-way for each memory sub partition (128 KB per memory sub partition). This gives 3MB L2 cache --gpgpu_cache:dl2 S:64:128:16,L:B:m:L:L,A:256:64,16:0,32 +-gpgpu_cache:dl2 S:64:128:16,L:B:m:L:P,A:256:64,16:0,32 -gpgpu_cache:dl2_texture_only 0 -gpgpu_dram_partition_queues 32:32:32:32 --perf_sim_memcpy 1 --memory_partition_indexing 0 +-gpgpu_perf_sim_memcpy 1 +-gpgpu_memory_partition_indexing 4 # 4 KB Inst. -gpgpu_cache:il1 N:8:128:4,L:R:f:N:L,S:2:48,4 +-gpgpu_inst_fetch_throughput 8 # 48 KB Tex # Note, TEX is deprected in Pascal, It is used for legacy apps only. Use L1D cache instead with .nc modifier or __ldg mehtod -gpgpu_tex_cache:l1 N:16:128:24,L:R:m:N:L,T:128:4,128:2 # 12 KB Const -gpgpu_const_cache:l1 N:128:64:2,L:R:f:N:L,S:2:64,4 - -# enable operand collector --gpgpu_operand_collector_num_units_sp 12 --gpgpu_operand_collector_num_units_sfu 6 --gpgpu_operand_collector_num_units_mem 8 --gpgpu_operand_collector_num_units_dp 6 --gpgpu_operand_collector_num_in_ports_sp 2 --gpgpu_operand_collector_num_out_ports_sp 2 --gpgpu_operand_collector_num_in_ports_sfu 2 --gpgpu_operand_collector_num_out_ports_sfu 2 --gpgpu_operand_collector_num_in_ports_mem 1 --gpgpu_operand_collector_num_out_ports_mem 1 --gpgpu_operand_collector_num_in_ports_dp 1 --gpgpu_operand_collector_num_out_ports_dp 1 --gpgpu_num_reg_banks 32 - -# shared memory bankconflict detection --gpgpu_shmem_num_banks 32 --gpgpu_shmem_limited_broadcast 0 --gpgpu_shmem_warp_parts 1 -# Use Pascal Coalsce arhitetecture --gpgpu_coalesce_arch 61 - -## In Pascal, a warp scheduler can issue 2 insts per cycle using 2 diff execution units --gpgpu_max_insn_issue_per_warp 2 --gpgpu_dual_issue_diff_exec_units 1 +-gpgpu_perfect_inst_const_cache 1 # interconnection -network_mode 1 -inter_config_file config_pascal_islip.icnt # memory partition latency config --rop_latency 120 +-gpgpu_l2_rop_latency 120 -dram_latency 100 # dram model config @@ -164,17 +161,8 @@ -dram_bnk_indexing_policy 0 -dram_bnkgrp_indexing_policy 1 -#-Seperate_Write_Queue_Enable 1 -#-Write_Queue_Size 64:56:32 - -# Pascal 102 has four schedulers per core --gpgpu_num_sched_per_core 2 -# Two Level Scheduler with active and pending pools -#-gpgpu_scheduler two_level_active:6:0:1 -# Loose round robbin scheduler -#-gpgpu_scheduler lrr -# Greedy then oldest scheduler --gpgpu_scheduler gto +#-dram_seperate_write_queue_enable 1 +#-dram_write_queue_size 64:56:32 # stat collection -gpgpu_memlatency_stat 14 diff --git a/configs/tested-cfgs/SM75_RTX2060/config_turing_islip.icnt b/configs/tested-cfgs/SM75_RTX2060/config_turing_islip.icnt new file mode 100644 index 0000000..eed1c34 --- /dev/null +++ b/configs/tested-cfgs/SM75_RTX2060/config_turing_islip.icnt @@ -0,0 +1,73 @@ +//52*1 fly with 32 flits per packet under gpgpusim injection mode +use_map = 0; +flit_size = 40; + +// currently we do not use this, see subnets below +network_count = 2; + +// Topology +topology = fly; +k = 52; +n = 1; + +// Routing + +routing_function = dest_tag; + +// Flow control + +num_vcs = 1; +vc_buf_size = 64; +input_buffer_size = 256; +ejection_buffer_size = 64; +boundary_buffer_size = 64; + +wait_for_tail_credit = 0; + +// Router architecture + +vc_allocator = islip; //separable_input_first; +sw_allocator = islip; //separable_input_first; +alloc_iters = 1; + +credit_delay = 0; +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; + +input_speedup = 1; +output_speedup = 1; +internal_speedup = 2.0; + +// Traffic, GPGPU-Sim does not use this + +traffic = uniform; +packet_size ={{1,2,3,4},{10,20}}; +packet_size_rate={{1,1,1,1},{2,1}}; + +// Simulation - Don't change + +sim_type = gpgpusim; +//sim_type = latency; +injection_rate = 0.1; + +subnets = 2; + +// Always use read and write no matter following line +//use_read_write = 1; + + +read_request_subnet = 0; +read_reply_subnet = 1; +write_request_subnet = 0; +write_reply_subnet = 1; + +read_request_begin_vc = 0; +read_request_end_vc = 0; +write_request_begin_vc = 0; +write_request_end_vc = 0; +read_reply_begin_vc = 0; +read_reply_end_vc = 0; +write_reply_begin_vc = 0; +write_reply_end_vc = 0; + diff --git a/configs/tested-cfgs/SM75_RTX2060/gpgpusim.config b/configs/tested-cfgs/SM75_RTX2060/gpgpusim.config new file mode 100644 index 0000000..6fe04ee --- /dev/null +++ b/configs/tested-cfgs/SM75_RTX2060/gpgpusim.config @@ -0,0 +1,184 @@ +# This config models the Turing RTX 2060 +# For more info about turing architecture: +# 1- https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/technologies/turing-architecture/NVIDIA-Turing-Architecture-Whitepaper.pdf +# 2- "RTX on—The NVIDIA Turing GPU", IEEE MICRO 2020 + +# functional simulator specification +-gpgpu_ptx_instruction_classification 0 +-gpgpu_ptx_sim_mode 0 +-gpgpu_ptx_force_max_capability 75 + +# Device Limits +-gpgpu_stack_size_limit 1024 +-gpgpu_heap_size_limit 8388608 +-gpgpu_runtime_sync_depth_limit 2 +-gpgpu_runtime_pending_launch_count_limit 2048 +-gpgpu_kernel_launch_latency 5000 + +# Compute Capability +-gpgpu_compute_capability_major 7 +-gpgpu_compute_capability_minor 5 + +# PTX execution-driven +-gpgpu_ptx_convert_to_ptxplus 0 +-gpgpu_ptx_save_converted_ptxplus 0 + +# high level architecture configuration +-gpgpu_n_clusters 30 +-gpgpu_n_cores_per_cluster 1 +-gpgpu_n_mem 12 +-gpgpu_n_sub_partition_per_mchannel 2 + +# volta clock domains +#-gpgpu_clock_domains <Core Clock>:<Interconnect Clock>:<L2 Clock>:<DRAM Clock> +-gpgpu_clock_domains 1365.0:1365.0:1365.0:3500.0 +# boost mode +# -gpgpu_clock_domains 1680.0:1680.0:1680.0:3500.0 + +# shader core pipeline config +-gpgpu_shader_registers 65536 +-gpgpu_registers_per_block 65536 +-gpgpu_occupancy_sm_number 75 + +# This implies a maximum of 32 warps/SM +-gpgpu_shader_core_pipeline 1024:32 +-gpgpu_shader_cta 32 +-gpgpu_simd_model 1 + +# Pipeline widths and number of FUs +# ID_OC_SP,ID_OC_DP,ID_OC_INT,ID_OC_SFU,ID_OC_MEM,OC_EX_SP,OC_EX_DP,OC_EX_INT,OC_EX_SFU,OC_EX_MEM,EX_WB,ID_OC_TENSOR_CORE,OC_EX_TENSOR_CORE +## Turing has 4 SP SIMD units, 4 INT units, 4 SFU units, 8 Tensor core units +## We need to scale the number of pipeline registers to be equal to the number of SP units +-gpgpu_pipeline_widths 4,0,4,4,4,4,0,4,4,4,8,4,4 +-gpgpu_num_sp_units 4 +-gpgpu_num_sfu_units 4 +-gpgpu_num_int_units 4 +-gpgpu_tensor_core_avail 1 +-gpgpu_num_tensor_core_units 4 + +# Instruction latencies and initiation intervals +# "ADD,MAX,MUL,MAD,DIV" +# All Div operations are executed on SFU unit +-ptx_opcode_latency_int 4,13,4,5,145,32 +-ptx_opcode_initiation_int 2,2,2,2,8,4 +-ptx_opcode_latency_fp 4,13,4,5,39 +-ptx_opcode_initiation_fp 2,2,2,2,4 +-ptx_opcode_latency_dp 8,19,8,8,330 +-ptx_opcode_initiation_dp 4,4,4,4,130 +-ptx_opcode_latency_sfu 100 +-ptx_opcode_initiation_sfu 8 +-ptx_opcode_latency_tesnor 64 +-ptx_opcode_initiation_tensor 64 + +# Turing has four schedulers per core +-gpgpu_num_sched_per_core 4 +# Greedy then oldest scheduler +-gpgpu_scheduler gto +## In Turing, a warp scheduler can issue 1 inst per cycle +-gpgpu_max_insn_issue_per_warp 1 +-gpgpu_dual_issue_diff_exec_units 1 + +# shared memory bankconflict detection +-gpgpu_shmem_num_banks 32 +-gpgpu_shmem_limited_broadcast 0 +-gpgpu_shmem_warp_parts 1 +-gpgpu_coalesce_arch 75 + +# Trung has sub core model, in which each scheduler has its own register file and EUs +# i.e. schedulers are isolated +-gpgpu_sub_core_model 1 +# disable specialized operand collectors and use generic operand collectors instead +-gpgpu_enable_specialized_operand_collector 0 +-gpgpu_operand_collector_num_units_gen 8 +-gpgpu_operand_collector_num_in_ports_gen 8 +-gpgpu_operand_collector_num_out_ports_gen 8 +# turing has 8 banks dual-port, 4 schedulers, two banks per scheduler +# we increase #banks to 16 to mitigate the effect of Regisrer File Cache (RFC) which we do not implement in the current version +-gpgpu_num_reg_banks 16 +-gpgpu_reg_file_port_throughput 2 + +# <nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>:<set_index_fn>,<mshr>:<N>:<merge>,<mq>:**<fifo_entry> +# ** Optional parameter - Required when mshr_type==Texture Fifo +-gpgpu_adaptive_cache_config 0 +-gpgpu_l1_banks 4 +-gpgpu_cache:dl1 S:1:128:512,L:L:s:N:L,A:256:8,16:0,32 +-gpgpu_shmem_size 65536 +-gpgpu_shmem_sizeDefault 65536 +-gpgpu_shmem_per_block 65536 +-gpgpu_gmem_skip_L1D 0 +-gpgpu_n_cluster_ejection_buffer_size 32 +-gpgpu_l1_latency 20 +-gpgpu_smem_latency 20 +-gpgpu_flush_l1_cache 1 + +# 64 sets, each 128 bytes 16-way for each memory sub partition (128 KB per memory sub partition). This gives us 3MB L2 cache +-gpgpu_cache:dl2 S:64:128:16,L:B:m:L:P,A:192:4,32:0,32 +-gpgpu_cache:dl2_texture_only 0 +-gpgpu_dram_partition_queues 64:64:64:64 +-gpgpu_perf_sim_memcpy 1 +-gpgpu_memory_partition_indexing 0 + +# 128 KB Inst. +-gpgpu_cache:il1 N:64:128:16,L:R:f:N:L,S:2:48,4 +-gpgpu_inst_fetch_throughput 4 +# 128 KB Tex +# Note, TEX is deprected in Volta, It is used for legacy apps only. Use L1D cache instead with .nc modifier or __ldg mehtod +-gpgpu_tex_cache:l1 N:4:128:256,L:R:m:N:L,T:512:8,128:2 +# 64 KB Const +-gpgpu_const_cache:l1 N:128:64:8,L:R:f:N:L,S:2:64,4 +-gpgpu_perfect_inst_const_cache 1 + +# interconnection +#-network_mode 1 +#-inter_config_file config_turing_islip.icnt +# use built-in local xbar +-network_mode 2 +-icnt_in_buffer_limit 512 +-icnt_out_buffer_limit 512 +-icnt_subnets 2 +-icnt_arbiter_algo 1 +-icnt_flit_size 40 + +# memory partition latency config +-gpgpu_l2_rop_latency 160 +-dram_latency 100 + +# dram model config +-gpgpu_dram_scheduler 1 +-gpgpu_frfcfs_dram_sched_queue_size 64 +-gpgpu_dram_return_queue_size 192 + +# Turing has GDDR6 +# http://monitorinsider.com/GDDR6.html +-gpgpu_n_mem_per_ctrlr 1 +-gpgpu_dram_buswidth 2 +-gpgpu_dram_burst_length 16 +-dram_data_command_freq_ratio 4 +-gpgpu_mem_address_mask 1 +-gpgpu_mem_addr_mapping dramid@8;00000000.00000000.00000000.00000000.0000RRRR.RRRRRRRR.RBBBCCCC.BCCSSSSS + +# Use the same GDDR5 timing, scaled to 3500MHZ +-gpgpu_dram_timing_opt "nbk=16:CCD=4:RRD=10:RCD=20:RAS=50:RP=20:RC=62: + CL=20:WL=8:CDLR=9:WR=20:nbkgrp=4:CCDL=4:RTPL=4" + +# select lower bits for bnkgrp to increase bnkgrp parallelism +-dram_bnk_indexing_policy 0 +-dram_bnkgrp_indexing_policy 1 + +#-dram_seperate_write_queue_enable 1 +#-dram_write_queue_size 64:56:32 + +# stat collection +-gpgpu_memlatency_stat 14 +-gpgpu_runtime_stat 500 +-enable_ptx_file_line_stats 1 +-visualizer_enabled 0 + +# power model configs, disable it untill we create a real energy model for Volta +-power_simulation_enabled 0 + +# tracing functionality +#-trace_enabled 1 +#-trace_components WARP_SCHEDULER,SCOREBOARD +#-trace_sampling_core 0 + diff --git a/configs/tested-cfgs/SM7_QV100/gpgpusim.config b/configs/tested-cfgs/SM7_QV100/gpgpusim.config index 91ff0b4..c4818d1 100644 --- a/configs/tested-cfgs/SM7_QV100/gpgpusim.config +++ b/configs/tested-cfgs/SM7_QV100/gpgpusim.config @@ -13,18 +13,19 @@ -gpgpu_ptx_sim_mode 0 -gpgpu_ptx_force_max_capability 70 - # Device Limits -gpgpu_stack_size_limit 1024 -gpgpu_heap_size_limit 8388608 -gpgpu_runtime_sync_depth_limit 2 -gpgpu_runtime_pending_launch_count_limit 2048 +-gpgpu_kernel_launch_latency 5000 +-gpgpu_TB_launch_latency 0 # Compute Capability -gpgpu_compute_capability_major 7 -gpgpu_compute_capability_minor 0 -# SASS execution (only supported with CUDA >= 4.0) +# PTX execution-driven -gpgpu_ptx_convert_to_ptxplus 0 -gpgpu_ptx_save_converted_ptxplus 0 @@ -36,8 +37,6 @@ # volta clock domains #-gpgpu_clock_domains <Core Clock>:<Interconnect Clock>:<L2 Clock>:<DRAM Clock> -# Volta NVIDIA TITANV clock domains are adopted from -# https://en.wikipedia.org/wiki/Volta_(microarchitecture) -gpgpu_clock_domains 1132.0:1132.0:1132.0:850.0 # boost mode # -gpgpu_clock_domains 1628.0:1628.0:1628.0:850.0 @@ -67,8 +66,6 @@ # Instruction latencies and initiation intervals # "ADD,MAX,MUL,MAD,DIV" # All Div operations are executed on SFU unit -# Throughput (initiation latency) are adopted from -# http://on-demand.gputechconf.com/gtc/2018/presentation/s8122-dissecting-the-volta-gpu-architecture-through-microbenchmarking.pdf -ptx_opcode_latency_int 4,13,4,5,145,21 -ptx_opcode_initiation_int 2,2,2,2,8,4 -ptx_opcode_latency_fp 4,13,4,5,39 @@ -80,6 +77,34 @@ -ptx_opcode_latency_tesnor 64 -ptx_opcode_initiation_tensor 64 +# Volta has sub core model, in which each scheduler has its own register file and EUs +# i.e. schedulers are isolated +-gpgpu_sub_core_model 1 +# disable specialized operand collectors and use generic operand collectors instead +-gpgpu_enable_specialized_operand_collector 0 +-gpgpu_operand_collector_num_units_gen 8 +-gpgpu_operand_collector_num_in_ports_gen 8 +-gpgpu_operand_collector_num_out_ports_gen 8 +# volta has 8 banks, 4 schedulers, two banks per scheduler +# we increase #banks to 16 to mitigate the effect of Regisrer File Cache (RFC) which we do not implement in the current version +-gpgpu_num_reg_banks 16 +-gpgpu_reg_file_port_throughput 2 + +# shared memory bankconflict detection +-gpgpu_shmem_num_banks 32 +-gpgpu_shmem_limited_broadcast 0 +-gpgpu_shmem_warp_parts 1 +-gpgpu_coalesce_arch 60 + +# Volta has four schedulers per core +-gpgpu_num_sched_per_core 4 +# Greedy then oldest scheduler +-gpgpu_scheduler gto +## In Volta, a warp scheduler can issue 1 inst per cycle +-gpgpu_max_insn_issue_per_warp 1 +-gpgpu_dual_issue_diff_exec_units 1 + +## L1/shared memory configuration # <nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>:<set_index_fn>,<mshr>:<N>:<merge>,<mq>:**<fifo_entry> # ** Optional parameter - Required when mshr_type==Texture Fifo # Defualt config is 32KB DL1 and 96KB shared memory @@ -87,67 +112,49 @@ # if the assigned shd mem = 0, then L1 cache = 128KB # For more info, see https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory-7-x # disable this mode in case of multi kernels/apps execution --adaptive_cache_config 1 +-gpgpu_adaptive_cache_config 1 # Volta unified cache has four banks --l1_banks 4 -#-mem_unit_ports 4 +-gpgpu_l1_banks 4 -gpgpu_cache:dl1 S:1:128:256,L:L:s:N:L,A:256:8,16:0,32 -gpgpu_shmem_size 98304 -gpgpu_shmem_sizeDefault 98304 -gpgpu_shmem_per_block 65536 --gmem_skip_L1D 0 --icnt_flit_size 40 +-gpgpu_gmem_skip_L1D 0 -gpgpu_n_cluster_ejection_buffer_size 32 --l1_latency 20 --smem_latency 20 +-gpgpu_l1_latency 20 +-gpgpu_smem_latency 20 -gpgpu_flush_l1_cache 1 # 32 sets, each 128 bytes 24-way for each memory sub partition (96 KB per memory sub partition). This gives us 6MB L2 cache --gpgpu_cache:dl2 S:32:128:24,L:B:m:L:L,A:192:4,32:0,32 +-gpgpu_cache:dl2 S:32:128:24,L:B:m:L:P,A:192:4,32:0,32 -gpgpu_cache:dl2_texture_only 0 -gpgpu_dram_partition_queues 64:64:64:64 --perf_sim_memcpy 1 --memory_partition_indexing 4 +-gpgpu_perf_sim_memcpy 1 +-gpgpu_memory_partition_indexing 2 # 128 KB Inst. -gpgpu_cache:il1 N:64:128:16,L:R:f:N:L,S:2:48,4 +-gpgpu_inst_fetch_throughput 4 # 128 KB Tex # Note, TEX is deprected in Volta, It is used for legacy apps only. Use L1D cache instead with .nc modifier or __ldg mehtod -gpgpu_tex_cache:l1 N:4:128:256,L:R:m:N:L,T:512:8,128:2 # 64 KB Const -gpgpu_const_cache:l1 N:128:64:8,L:R:f:N:L,S:2:64,4 - -# Volta has sub core model, in which each scheduler has its own register file and EUs -# i.e. schedulers are isolated --sub_core_model 1 -# disable specialized operand collectors and use generic operand collectors instead --enable_specialized_operand_collector 0 --gpgpu_operand_collector_num_units_gen 32 --gpgpu_operand_collector_num_in_ports_gen 8 --gpgpu_operand_collector_num_out_ports_gen 8 -# Volta has 8 banks, 4 schedulers, two banks per scheduler -# However, since we do not model register file cache (RFC), we increase the number of banks to 32 to -# resuce banks conflits, mitigate RFC impact, and matche the hardware performance. To Do: RFC --gpgpu_num_reg_banks 32 - -# shared memory bankconflict detection --gpgpu_shmem_num_banks 32 --gpgpu_shmem_limited_broadcast 0 --gpgpu_shmem_warp_parts 1 --gpgpu_coalesce_arch 60 - -## In Volta, a warp scheduler can issue 1 inst per cycle --gpgpu_max_insn_issue_per_warp 1 --gpgpu_dual_issue_diff_exec_units 1 +-gpgpu_perfect_inst_const_cache 1 # interconnection --network_mode 1 --inter_config_file config_volta_islip.icnt -# for local xbar, use: -# "-network_mode 2 -inct_in_buffer_limit 512 -inct_out_buffer_limit 512 -inct_subnets 2" +#-network_mode 1 +#-inter_config_file config_volta_islip.icnt +# use built-in local xbar +-network_mode 2 +-icnt_in_buffer_limit 512 +-icnt_out_buffer_limit 512 +-icnt_subnets 2 +-icnt_flit_size 40 +-icnt_arbiter_algo 1 # memory partition latency config --rop_latency 160 +-gpgpu_l2_rop_latency 160 -dram_latency 100 # dram model config @@ -174,22 +181,13 @@ CL=12:WL=2:CDLR=3:WR=10:nbkgrp=4:CCDL=2:RTPL=3" # HBM has dual bus interface, in which it can issue two col and row commands at a time --dual_bus_interface 1 +-dram_dual_bus_interface 1 # select lower bits for bnkgrp to increase bnkgrp parallelism -dram_bnk_indexing_policy 0 -dram_bnkgrp_indexing_policy 1 -#-Seperate_Write_Queue_Enable 1 -#-Write_Queue_Size 64:56:32 - -# Volta has four schedulers per core --gpgpu_num_sched_per_core 4 -# Two Level Scheduler with active and pending pools -#-gpgpu_scheduler two_level_active:6:0:1 -# Loose round robbin scheduler -#-gpgpu_scheduler lrr -# Greedy then oldest scheduler --gpgpu_scheduler gto +#-dram_seperate_write_queue_enable 1 +#-dram_write_queue_size 64:56:32 # stat collection -gpgpu_memlatency_stat 14 diff --git a/configs/tested-cfgs/SM7_TITANV/gpgpusim.config b/configs/tested-cfgs/SM7_TITANV/gpgpusim.config index a77ab74..3fa51ee 100644 --- a/configs/tested-cfgs/SM7_TITANV/gpgpusim.config +++ b/configs/tested-cfgs/SM7_TITANV/gpgpusim.config @@ -13,7 +13,6 @@ -gpgpu_ptx_sim_mode 0 -gpgpu_ptx_force_max_capability 70 - # Device Limits -gpgpu_stack_size_limit 1024 -gpgpu_heap_size_limit 8388608 @@ -67,7 +66,7 @@ # Instruction latencies and initiation intervals # "ADD,MAX,MUL,MAD,DIV" # All Div operations are executed on SFU unit -# Throughput (initiation latency except shfl) are adopted from +# Throughput (initiation latency) are adopted from # http://on-demand.gputechconf.com/gtc/2018/presentation/s8122-dissecting-the-volta-gpu-architecture-through-microbenchmarking.pdf -ptx_opcode_latency_int 4,13,4,5,145,32 -ptx_opcode_initiation_int 2,2,2,2,8,4 @@ -80,6 +79,33 @@ -ptx_opcode_latency_tesnor 64 -ptx_opcode_initiation_tensor 64 +# Volta has sub core model, in which each scheduler has its own register file and EUs +# i.e. schedulers are isolated +-gpgpu_sub_core_model 1 +# disable specialized operand collectors and use generic operand collectors instead +-gpgpu_enable_specialized_operand_collector 0 +-gpgpu_operand_collector_num_units_gen 8 +-gpgpu_operand_collector_num_in_ports_gen 8 +-gpgpu_operand_collector_num_out_ports_gen 8 +# volta has 8 banks, 4 schedulers, two banks per scheduler +-gpgpu_num_reg_banks 8 +-gpgpu_reg_file_port_throughput 2 + +# shared memory bankconflict detection +-gpgpu_shmem_num_banks 32 +-gpgpu_shmem_limited_broadcast 0 +-gpgpu_shmem_warp_parts 1 +-gpgpu_coalesce_arch 60 + +# Volta has four schedulers per core +-gpgpu_num_sched_per_core 4 +# Greedy then oldest scheduler +-gpgpu_scheduler gto +## In Volta, a warp scheduler can issue 1 inst per cycle +-gpgpu_max_insn_issue_per_warp 1 +-gpgpu_dual_issue_diff_exec_units 1 + +## L1/shared memory configuration # <nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>:<set_index_fn>,<mshr>:<N>:<merge>,<mq>:**<fifo_entry> # ** Optional parameter - Required when mshr_type==Texture Fifo # Defualt config is 32KB DL1 and 96KB shared memory @@ -87,65 +113,49 @@ # if the assigned shd mem = 0, then L1 cache = 128KB # For more info, see https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory-7-x # disable this mode in case of multi kernels/apps execution --adaptive_cache_config 1 +-gpgpu_adaptive_cache_config 1 # Volta unified cache has four banks --l1_banks 4 -#-mem_unit_ports 4 +-gpgpu_l1_banks 4 -gpgpu_cache:dl1 S:1:128:256,L:L:s:N:L,A:256:8,16:0,32 -gpgpu_shmem_size 98304 -gpgpu_shmem_sizeDefault 98304 -gpgpu_shmem_per_block 65536 --gmem_skip_L1D 0 --icnt_flit_size 40 +-gpgpu_gmem_skip_L1D 0 -gpgpu_n_cluster_ejection_buffer_size 32 --l1_latency 20 --smem_latency 20 +-gpgpu_l1_latency 20 +-gpgpu_smem_latency 20 -gpgpu_flush_l1_cache 1 # 32 sets, each 128 bytes 24-way for each memory sub partition (96 KB per memory sub partition). This gives us 4.5MB L2 cache --gpgpu_cache:dl2 S:32:128:24,L:B:m:L:L,A:192:4,32:0,32 +-gpgpu_cache:dl2 S:32:128:24,L:B:m:L:P,A:192:4,32:0,32 -gpgpu_cache:dl2_texture_only 0 -gpgpu_dram_partition_queues 64:64:64:64 --perf_sim_memcpy 1 --memory_partition_indexing 4 +-gpgpu_perf_sim_memcpy 1 +-gpgpu_memory_partition_indexing 2 # 128 KB Inst. -gpgpu_cache:il1 N:64:128:16,L:R:f:N:L,S:2:48,4 +-gpgpu_inst_fetch_throughput 4 # 48 KB Tex # Note, TEX is deprected in Volta, It is used for legacy apps only. Use L1D cache instead with .nc modifier or __ldg mehtod -gpgpu_tex_cache:l1 N:4:128:256,L:R:m:N:L,T:512:8,128:2 # 64 KB Const -gpgpu_const_cache:l1 N:128:64:8,L:R:f:N:L,S:2:64,4 - -# Volta has sub core model, in which each scheduler has its own register file and EUs -# i.e. schedulers are isolated --sub_core_model 1 -# disable specialized operand collectors and use generic operand collectors instead --enable_specialized_operand_collector 0 --gpgpu_operand_collector_num_units_gen 8 --gpgpu_operand_collector_num_in_ports_gen 8 --gpgpu_operand_collector_num_out_ports_gen 8 -# volta has 8 banks, 4 schedulers, two banks per scheduler --gpgpu_num_reg_banks 8 - -# shared memory bankconflict detection --gpgpu_shmem_num_banks 32 --gpgpu_shmem_limited_broadcast 0 --gpgpu_shmem_warp_parts 1 --gpgpu_coalesce_arch 60 - -## In Volta, a warp scheduler can issue 1 inst per cycle --gpgpu_max_insn_issue_per_warp 1 --gpgpu_dual_issue_diff_exec_units 1 +-gpgpu_perfect_inst_const_cache 1 # interconnection --network_mode 1 --inter_config_file config_volta_islip.icnt -# for local xbar, use: -# "-network_mode 2 -inct_in_buffer_limit 512 -inct_out_buffer_limit 512 -inct_subnets 2" +#-network_mode 1 +#-inter_config_file config_volta_islip.icnt +# use built-in local xbar +-network_mode 2 +-icnt_in_buffer_limit 512 +-icnt_out_buffer_limit 512 +-icnt_subnets 2 +-icnt_flit_size 40 +-icnt_arbiter_algo 1 # memory partition latency config --rop_latency 160 +-gpgpu_l2_rop_latency 160 -dram_latency 100 # dram model config @@ -172,22 +182,13 @@ CL=12:WL=2:CDLR=3:WR=10:nbkgrp=4:CCDL=2:RTPL=3" # HBM has dual bus interface, in which it can issue two col and row commands at a time --dual_bus_interface 1 +-dram_dual_bus_interface 1 # select lower bits for bnkgrp to increase bnkgrp parallelism --dram_bnk_indexing_policy 0 +-dram_bnk_indexing_policy 1 -dram_bnkgrp_indexing_policy 1 -#-Seperate_Write_Queue_Enable 1 -#-Write_Queue_Size 64:56:32 - -# Volta has four schedulers per core --gpgpu_num_sched_per_core 4 -# Two Level Scheduler with active and pending pools -#-gpgpu_scheduler two_level_active:6:0:1 -# Loose round robbin scheduler -#-gpgpu_scheduler lrr -# Greedy then oldest scheduler --gpgpu_scheduler gto +-dram_seperate_write_queue_enable 1 +-dram_write_queue_size 128:108:32 # stat collection -gpgpu_memlatency_stat 14 @@ -203,3 +204,4 @@ #-trace_components WARP_SCHEDULER,SCOREBOARD #-trace_sampling_core 0 + diff --git a/cuobjdump_to_ptxplus/cuobjdumpInst.cc b/cuobjdump_to_ptxplus/cuobjdumpInst.cc index 392f829..eb70199 100644 --- a/cuobjdump_to_ptxplus/cuobjdumpInst.cc +++ b/cuobjdump_to_ptxplus/cuobjdumpInst.cc @@ -2071,6 +2071,11 @@ void cuobjdumpInst::printCuobjdumpPtxPlus(std::list<std::string> labelList, std: printCuobjdumpTypeModifiers(); printCuobjdumpOperands(); output(";"); + } else if(m_base == "ACTIVEMASK") { + printCuobjdumpPredicate(); + output("activemask.b32"); + printCuobjdumpOperands(); + output(";"); } else if(m_base == "DFMA") { diff --git a/format-code.sh b/format-code.sh index 39c24e4..fb1cc90 100755 --- a/format-code.sh +++ b/format-code.sh @@ -10,3 +10,6 @@ clang-format -i ${THIS_DIR}/src/cuda-sim/*.h clang-format -i ${THIS_DIR}/src/cuda-sim/*.cc clang-format -i ${THIS_DIR}/src/gpuwattch/*.h clang-format -i ${THIS_DIR}/src/gpuwattch/*.cc +clang-format -i ${THIS_DIR}/src/trace-driven/*.h +clang-format -i ${THIS_DIR}/src/trace-driven/*.cc +clang-format -i ${THIS_DIR}/src/trace-driven/ISA_Def/*.h diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index 7922bc5..e0e1d23 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -205,8 +205,8 @@ gpgpu_t::gpgpu_t(const gpgpu_functional_sim_config &config, gpgpu_context *ctx) gpu_tot_sim_cycle = 0; } -address_type line_size_based_tag_func(new_addr_type address, - new_addr_type line_size) { +new_addr_type line_size_based_tag_func(new_addr_type address, + new_addr_type line_size) { // gives the tag for an address based on a given line size return address & ~(line_size - 1); } @@ -257,6 +257,7 @@ void warp_inst_t::do_atomic(bool forceDo) { void warp_inst_t::do_atomic(const active_mask_t &access_mask, bool forceDo) { assert(m_isatomic && (!m_empty || forceDo)); + if (!should_do_atomic) return; for (unsigned i = 0; i < m_config->warp_size; i++) { if (access_mask.test(i)) { dram_callback_t &cb = m_per_scalar_thread[i].callback; @@ -447,7 +448,7 @@ void warp_inst_t::generate_mem_accesses() { for (unsigned thread = 0; thread < m_config->warp_size; thread++) { if (!active(thread)) continue; new_addr_type addr = m_per_scalar_thread[thread].memreqaddr[0]; - unsigned block_address = line_size_based_tag_func(addr, cache_block_size); + new_addr_type block_address = line_size_based_tag_func(addr, cache_block_size); accesses[block_address].set(thread); unsigned idx = addr - block_address; for (unsigned i = 0; i < data_size; i++) byte_mask.set(idx + i); @@ -529,20 +530,37 @@ void warp_inst_t::memory_coalescing_arch(bool is_write, (m_per_scalar_thread[thread].memreqaddr[access] != 0); access++) { new_addr_type addr = m_per_scalar_thread[thread].memreqaddr[access]; - unsigned block_address = line_size_based_tag_func(addr, segment_size); + new_addr_type block_address = line_size_based_tag_func(addr, segment_size); unsigned chunk = (addr & 127) / 32; // which 32-byte chunk within in a 128-byte // chunk does this thread access? transaction_info &info = subwarp_transactions[block_address]; // can only write to one segment - assert(block_address == line_size_based_tag_func( - addr + data_size_coales - 1, segment_size)); + // it seems like in trace driven, a thread can write to more than one + // segment assert(block_address == + // line_size_based_tag_func(addr+data_size_coales-1,segment_size)); info.chunks.set(chunk); info.active.set(thread); unsigned idx = (addr & 127); - for (unsigned i = 0; i < data_size_coales; i++) info.bytes.set(idx + i); + for (unsigned i = 0; i < data_size_coales; i++) + if ((idx + i) < MAX_MEMORY_ACCESS_SIZE) info.bytes.set(idx + i); + + // it seems like in trace driven, a thread can write to more than one + // segment handle this special case + if (block_address != line_size_based_tag_func( + addr + data_size_coales - 1, segment_size)) { + addr = addr + data_size_coales - 1; + new_addr_type block_address = line_size_based_tag_func(addr, segment_size); + unsigned chunk = (addr & 127) / 32; + transaction_info &info = subwarp_transactions[block_address]; + info.chunks.set(chunk); + info.active.set(thread); + unsigned idx = (addr & 127); + for (unsigned i = 0; i < data_size_coales; i++) + if ((idx + i) < MAX_MEMORY_ACCESS_SIZE) info.bytes.set(idx + i); + } } } @@ -607,7 +625,7 @@ void warp_inst_t::memory_coalescing_arch_atomic(bool is_write, if (!active(thread)) continue; new_addr_type addr = m_per_scalar_thread[thread].memreqaddr[0]; - unsigned block_address = line_size_based_tag_func(addr, segment_size); + new_addr_type block_address = line_size_based_tag_func(addr, segment_size); unsigned chunk = (addr & 127) / 32; // which 32-byte chunk within in a 128-byte chunk // does this thread access? @@ -746,6 +764,10 @@ kernel_info_t::kernel_info_t(dim3 gridDim, dim3 blockDim, // Jin: launch latency management m_launch_latency = entry->gpgpu_ctx->device_runtime->g_kernel_launch_latency; + m_kernel_TB_latency = + entry->gpgpu_ctx->device_runtime->g_kernel_launch_latency + + num_blocks() * entry->gpgpu_ctx->device_runtime->g_TB_launch_latency; + cache_config_set = false; } @@ -773,6 +795,10 @@ kernel_info_t::kernel_info_t( // Jin: launch latency management m_launch_latency = entry->gpgpu_ctx->device_runtime->g_kernel_launch_latency; + m_kernel_TB_latency = + entry->gpgpu_ctx->device_runtime->g_kernel_launch_latency + + num_blocks() * entry->gpgpu_ctx->device_runtime->g_TB_launch_latency; + cache_config_set = false; m_NameToCudaArray = nameToCudaArray; m_NameToTextureInfo = nameToTextureInfo; diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index 46534ab..c012de0 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -65,7 +65,7 @@ enum FuncCache { FuncCachePreferL1 = 2 }; -enum AdaptiveCache { FIXED = 0, VOLTA = 1 }; +enum AdaptiveCache { FIXED = 0, ADAPTIVE_VOLTA = 1 }; #ifdef __cplusplus @@ -75,10 +75,12 @@ enum AdaptiveCache { FIXED = 0, VOLTA = 1 }; typedef unsigned long long new_addr_type; typedef unsigned long long cudaTextureObject_t; -typedef unsigned address_type; -typedef unsigned addr_t; +typedef unsigned long long address_type; +typedef unsigned long long addr_t; // the following are operations the timing model can see +#define SPECIALIZED_UNIT_NUM 8 +#define SPEC_UNIT_START_ID 100 enum uarch_op_t { NO_OP = -1, @@ -97,7 +99,16 @@ enum uarch_op_t { BARRIER_OP, MEMORY_BARRIER_OP, CALL_OPS, - RET_OPS + RET_OPS, + EXIT_OPS, + SPECIALIZED_UNIT_1_OP = SPEC_UNIT_START_ID, + SPECIALIZED_UNIT_2_OP, + SPECIALIZED_UNIT_3_OP, + SPECIALIZED_UNIT_4_OP, + SPECIALIZED_UNIT_5_OP, + SPECIALIZED_UNIT_6_OP, + SPECIALIZED_UNIT_7_OP, + SPECIALIZED_UNIT_8_OP }; typedef enum uarch_op_t op_type; @@ -134,7 +145,8 @@ enum operation_pipeline_t { INTP__OP, SFU__OP, TENSOR_CORE__OP, - MEM__OP + MEM__OP, + SPECIALIZED__OP, }; typedef enum operation_pipeline_t operation_pipeline; enum mem_operation_t { NOT_TEX, TEX }; @@ -326,6 +338,9 @@ class kernel_info_t { unsigned m_launch_latency; mutable bool cache_config_set; + + unsigned m_kernel_TB_latency; // this used for any CPU-GPU kernel latency and + // counted in the gpu_cycle }; class core_config { @@ -618,6 +633,8 @@ class gpgpu_t { return m_NameToTextureInfo; } + virtual ~gpgpu_t() {} + protected: const gpgpu_functional_sim_config &m_function_model_config; FILE *ptx_inst_debug_file; @@ -993,6 +1010,7 @@ class warp_inst_t : public inst_t { m_cache_hit = false; m_is_printf = false; m_is_cdp = 0; + should_do_atomic = true; } virtual ~warp_inst_t() {} @@ -1132,6 +1150,7 @@ class warp_inst_t : public inst_t { void print(FILE *fout) const; unsigned get_uid() const { return m_uid; } unsigned get_schd_id() const { return m_scheduler_id; } + active_mask_t get_warp_active_mask() const { return m_warp_active_mask; } protected: unsigned m_uid; @@ -1140,6 +1159,7 @@ class warp_inst_t : public inst_t { unsigned long long issue_cycle; unsigned cycles; // used for implementing initiation interval delay bool m_isatomic; + bool should_do_atomic; bool m_is_printf; unsigned m_warp_id; unsigned m_dynamic_warp_id; @@ -1228,7 +1248,7 @@ class core_t { } void execute_warp_inst_t(warp_inst_t &inst, unsigned warpId = (unsigned)-1); bool ptx_thread_done(unsigned hw_thread_id) const; - void updateSIMTStack(unsigned warpId, warp_inst_t *inst); + virtual void updateSIMTStack(unsigned warpId, warp_inst_t *inst); void initilizeSIMTStack(unsigned warp_count, unsigned warps_size); void deleteSIMTStack(); warp_inst_t getExecuteWarp(unsigned warpId); diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc index 75dd3c8..71f0703 100644 --- a/src/cuda-sim/cuda-sim.cc +++ b/src/cuda-sim/cuda-sim.cc @@ -1741,7 +1741,7 @@ void ptx_thread_info::ptx_exec_inst(warp_inst_t &inst, unsigned lane_id) { } else { const ptx_instruction *pI_saved = pI; ptx_instruction *pJ = NULL; - if (pI->get_opcode() == VOTE_OP) { + if (pI->get_opcode() == VOTE_OP || pI->get_opcode() == ACTIVEMASK_OP) { pJ = new ptx_instruction(*pI); *((warp_inst_t *)pJ) = inst; // copy active mask information pI = pJ; diff --git a/src/cuda-sim/cuda_device_runtime.h b/src/cuda-sim/cuda_device_runtime.h index 1d661b2..b06dd24 100644 --- a/src/cuda-sim/cuda_device_runtime.h +++ b/src/cuda-sim/cuda_device_runtime.h @@ -43,6 +43,7 @@ class cuda_device_runtime { std::map<void*, device_launch_config_t> g_cuda_device_launch_param_map; std::list<device_launch_operation_t> g_cuda_device_launch_op; unsigned g_kernel_launch_latency; + unsigned g_TB_launch_latency; unsigned long long g_max_total_param_size; bool g_cdp_enabled; diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc index bf9a040..8936fa8 100644 --- a/src/cuda-sim/instructions.cc +++ b/src/cuda-sim/instructions.cc @@ -166,6 +166,8 @@ void inst_not_implemented(const ptx_instruction *pI); ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo, operand_info dstInfo, unsigned type, ptx_thread_info *thread); + +void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread, int op_code); void sign_extend(ptx_reg_t &data, unsigned src_size, const operand_info &dst); @@ -1709,8 +1711,40 @@ void bfi_impl(const ptx_instruction *pI, ptx_thread_info *thread) { } thread->set_operand_value(dst, data, i_type, thread, pI); } -void bfind_impl(const ptx_instruction *pI, ptx_thread_info *thread) { - inst_not_implemented(pI); +void bfind_impl(const ptx_instruction *pI, ptx_thread_info *thread) +{ + const operand_info &dst = pI->dst(); + const operand_info &src1 = pI->src1(); + const unsigned i_type = pI->get_type(); + + const ptx_reg_t src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1); + const int msb = ( i_type == U32_TYPE || i_type == S32_TYPE) ? 31 : 63; + + unsigned long a = 0; + switch (i_type) + { + case S32_TYPE: a = src1_data.s32; break; + case U32_TYPE: a = src1_data.u32; break; + case S64_TYPE: a = src1_data.s64; break; + case U64_TYPE: a = src1_data.u64; break; + default: assert(false); abort(); + } + + // negate negative signed inputs + if ( ( i_type == S32_TYPE || i_type == S64_TYPE ) && ( a & ( 1 << msb ) ) ) { + a = ~a; + } + uint32_t d_data = 0xffffffff; + for (uint32_t i = msb; i >= 0; i--) { + if (a & (1<<i)) { d_data = i; break; } + } + + // if (.shiftamt && d != 0xffffffff) { d = msb - d; } + + // store d + thread->set_operand_value(dst, d_data, U32_TYPE, thread, pI); + + } void bra_impl(const ptx_instruction *pI, ptx_thread_info *thread) { @@ -6301,11 +6335,17 @@ void vadd_impl(const ptx_instruction *pI, ptx_thread_info *thread) { void vmad_impl(const ptx_instruction *pI, ptx_thread_info *thread) { inst_not_implemented(pI); } -void vmax_impl(const ptx_instruction *pI, ptx_thread_info *thread) { - inst_not_implemented(pI); + +#define VMAX 0 +#define VMIN 1 + +void vmax_impl(const ptx_instruction *pI, ptx_thread_info *thread) +{ + video_mem_instruction(pI, thread, VMAX); } -void vmin_impl(const ptx_instruction *pI, ptx_thread_info *thread) { - inst_not_implemented(pI); +void vmin_impl(const ptx_instruction *pI, ptx_thread_info *thread) +{ + video_mem_instruction(pI, thread, VMIN); } void vset_impl(const ptx_instruction *pI, ptx_thread_info *thread) { inst_not_implemented(pI); @@ -6400,6 +6440,15 @@ void vote_impl(const ptx_instruction *pI, ptx_thread_info *thread) { } } +void activemask_impl( const ptx_instruction *pI, ptx_thread_info *thread ) +{ + active_mask_t l_activemask_bitset = pI->get_warp_active_mask(); + uint32_t l_activemask_uint = static_cast<uint32_t>(l_activemask_bitset.to_ulong()); + + const operand_info &dst = pI->dst(); + thread->set_operand_value(dst, l_activemask_uint, U32_TYPE, thread, pI); +} + void xor_impl(const ptx_instruction *pI, ptx_thread_info *thread) { ptx_reg_t src1_data, src2_data, data; @@ -6477,3 +6526,80 @@ ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo, return result; } + +void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread, int op_code) +{ + const operand_info &dst = pI->dst(); // d + const operand_info &src1 = pI->src1(); // a + const operand_info &src2 = pI->src2(); // b + const operand_info &src3 = pI->src3(); // c + + const unsigned i_type = pI->get_type(); + + std::list<int> scalar_type; + std::list<int> options; + + ptx_reg_t a, b, ta, tb, c, data; + + a = thread->get_operand_value(src1, dst, i_type, thread, 1); + b = thread->get_operand_value(src2, dst, i_type, thread, 1); + c = thread->get_operand_value(src3, dst, i_type, thread, 1); + + // TODO: implement this + // ta = partSelectSignExtend( a, atype ); + // tb = partSelectSignExtend( b, btype ); + ta = a; + tb = b; + + options = pI->get_options(); + assert(options.size() == 1); + + auto option = options.begin(); + assert(*option == ATOMIC_MAX || *option == ATOMIC_MIN); + + switch ( i_type ) { + case S32_TYPE: { + // assert all operands are S32_TYPE: + scalar_type = pI->get_scalar_type(); + for (std::list<int>::iterator scalar = scalar_type.begin(); scalar != scalar_type.end(); scalar++) + { + assert(*scalar == S32_TYPE); + } + assert(scalar_type.size() == 3); + scalar_type.clear(); + + switch (op_code) + { + case VMAX: + data.s32 = MY_MAX_I(ta.s32, tb.s32); + break; + case VMIN: + data.s32 = MY_MIN_I(ta.s32, tb.s32); + break; + default: + assert(0); + } + + switch (*option) + { + case ATOMIC_MAX: + data.s32 = MY_MAX_I(data.s32, c.s32); + break; + case ATOMIC_MIN: + data.s32 = MY_MIN_I(data.s32, c.s32); + break; + default: + assert(0); // not yet implemented + } + break; + + } + default: + assert(0); // not yet implemented + } + + thread->set_operand_value(dst, data, i_type, thread, pI); + + return; +} + diff --git a/src/cuda-sim/opcodes.def b/src/cuda-sim/opcodes.def index c4d6a83..f5bf156 100644 --- a/src/cuda-sim/opcodes.def +++ b/src/cuda-sim/opcodes.def @@ -129,6 +129,7 @@ OP_DEF(VSHL_OP,vshl_impl,"vshl",0,11) OP_DEF(VSHR_OP,vshr_impl,"vshr",0,11) OP_DEF(VSUB_OP,vsub_impl,"vsub",0,11) OP_DEF(VOTE_OP,vote_impl,"vote",0,3) +OP_DEF(ACTIVEMASK_OP,activemask_impl,"activemask",1,3) OP_DEF(XOR_OP,xor_impl,"xor",1,1) OP_DEF(NOP_OP,nop_impl,"nop",0,7) OP_DEF(BREAK_OP,break_impl,"break",0,3) diff --git a/src/cuda-sim/ptx-stats.cc b/src/cuda-sim/ptx-stats.cc index 9f7e760..3e96984 100644 --- a/src/cuda-sim/ptx-stats.cc +++ b/src/cuda-sim/ptx-stats.cc @@ -168,9 +168,10 @@ void ptx_file_line_stats_add_exec_count(const ptx_instruction *pInsn) { void ptx_stats::ptx_file_line_stats_add_latency(unsigned pc, unsigned latency) { const ptx_instruction *pInsn = gpgpu_ctx->pc_to_instruction(pc); - ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), - pInsn->source_line())] - .latency += latency; + if (pInsn != NULL) + ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), + pInsn->source_line())] + .latency += latency; } // attribute dram traffic to this ptx instruction (specified by the pc) @@ -179,9 +180,10 @@ void ptx_stats::ptx_file_line_stats_add_dram_traffic(unsigned pc, unsigned dram_traffic) { const ptx_instruction *pInsn = gpgpu_ctx->pc_to_instruction(pc); - ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), - pInsn->source_line())] - .dram_traffic += dram_traffic; + if (pInsn != NULL) + ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), + pInsn->source_line())] + .dram_traffic += dram_traffic; } // attribute the number of shared memory access cycles to a ptx instruction @@ -191,10 +193,12 @@ void ptx_stats::ptx_file_line_stats_add_smem_bank_conflict( unsigned pc, unsigned n_way_bkconflict) { const ptx_instruction *pInsn = gpgpu_ctx->pc_to_instruction(pc); - ptx_file_line_stats &line_stats = ptx_file_line_stats_tracker[ptx_file_line( - pInsn->source_file(), pInsn->source_line())]; - line_stats.smem_n_way_bank_conflict_total += n_way_bkconflict; - line_stats.smem_warp_count += 1; + if (pInsn != NULL) { + ptx_file_line_stats &line_stats = ptx_file_line_stats_tracker[ptx_file_line( + pInsn->source_file(), pInsn->source_line())]; + line_stats.smem_n_way_bank_conflict_total += n_way_bkconflict; + line_stats.smem_warp_count += 1; + } } // attribute a non-coalesced mem access to a ptx instruction @@ -204,10 +208,12 @@ void ptx_stats::ptx_file_line_stats_add_uncoalesced_gmem(unsigned pc, unsigned n_access) { const ptx_instruction *pInsn = gpgpu_ctx->pc_to_instruction(pc); - ptx_file_line_stats &line_stats = ptx_file_line_stats_tracker[ptx_file_line( - pInsn->source_file(), pInsn->source_line())]; - line_stats.gmem_n_access_total += n_access; - line_stats.gmem_warp_count += 1; + if (pInsn != NULL) { + ptx_file_line_stats &line_stats = ptx_file_line_stats_tracker[ptx_file_line( + pInsn->source_file(), pInsn->source_line())]; + line_stats.gmem_n_access_total += n_access; + line_stats.gmem_warp_count += 1; + } } // a class that tracks the inflight memory instructions of a shader core diff --git a/src/cuda-sim/ptx.l b/src/cuda-sim/ptx.l index 2dadda4..6754045 100644 --- a/src/cuda-sim/ptx.l +++ b/src/cuda-sim/ptx.l @@ -158,6 +158,7 @@ vshl TC; yylval->int_value = VSHL_OP; return OPCODE; vshr TC; yylval->int_value = VSHR_OP; return OPCODE; vsub TC; yylval->int_value = VSUB_OP; return OPCODE; vote TC; yylval->int_value = VOTE_OP; return OPCODE; +activemask TC; yylval->int_value = ACTIVEMASK_OP; return OPCODE; xor TC; yylval->int_value = XOR_OP; return OPCODE; nop TC; yylval->int_value = NOP_OP; return OPCODE; break TC; yylval->int_value = BREAK_OP; return OPCODE; diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc index aa1c25a..e5b5fb7 100644 --- a/src/cuda-sim/ptx_ir.cc +++ b/src/cuda-sim/ptx_ir.cc @@ -1147,7 +1147,8 @@ static std::list<operand_info> check_operands( const std::list<operand_info> &operands, gpgpu_context *ctx) { static int g_warn_literal_operands_two_type_inst; if ((opcode == CVT_OP) || (opcode == SET_OP) || (opcode == SLCT_OP) || - (opcode == TEX_OP) || (opcode == MMA_OP) || (opcode == DP4A_OP)) { + (opcode == TEX_OP) || (opcode == MMA_OP) || (opcode == DP4A_OP) || + (opcode == VMIN_OP) || (opcode == VMAX_OP) ) { // just make sure these do not have have const operands... if (!g_warn_literal_operands_two_type_inst) { std::list<operand_info>::const_iterator o; diff --git a/src/cuda-sim/ptx_ir.h b/src/cuda-sim/ptx_ir.h index 6627847..4243941 100644 --- a/src/cuda-sim/ptx_ir.h +++ b/src/cuda-sim/ptx_ir.h @@ -966,6 +966,9 @@ class ptx_instruction : public warp_inst_t { int get_pred_mod() const { return m_pred_mod; } const char *get_source() const { return m_source.c_str(); } + const std::list<int> get_scalar_type() const {return m_scalar_type;} + const std::list<int> get_options() const {return m_options;} + typedef std::vector<operand_info>::const_iterator const_iterator; const_iterator op_iter_begin() const { return m_operands.begin(); } @@ -1336,12 +1339,12 @@ class function_info { memory_space *param_mem, gpgpu_t *gpu, dim3 gridDim, dim3 blockDim); - const struct gpgpu_ptx_sim_info *get_kernel_info() const { + virtual const struct gpgpu_ptx_sim_info *get_kernel_info() const { assert(m_kernel_info.maxthreads == maxnt_id); return &m_kernel_info; } - const void set_kernel_info(const struct gpgpu_ptx_sim_info &info) { + virtual const void set_kernel_info(const struct gpgpu_ptx_sim_info &info) { m_kernel_info = info; m_kernel_info.ptx_version = 10 * get_ptx_version().ver(); m_kernel_info.sm_target = get_ptx_version().target(); @@ -1377,6 +1380,11 @@ class function_info { // backward pointer class gpgpu_context *gpgpu_ctx; + protected: + // Registers/shmem/etc. used (from ptxas -v), loaded from ___.ptxinfo along + // with ___.ptx + struct gpgpu_ptx_sim_info m_kernel_info; + private: unsigned maxnt_id; unsigned m_uid; @@ -1402,7 +1410,7 @@ class function_info { // Registers/shmem/etc. used (from ptxas -v), loaded from ___.ptxinfo along // with ___.ptx - struct gpgpu_ptx_sim_info m_kernel_info; + // with ___.ptx symbol_table *m_symtab; diff --git a/src/cuda-sim/ptx_loader.cc b/src/cuda-sim/ptx_loader.cc index 372bda4..4e91763 100644 --- a/src/cuda-sim/ptx_loader.cc +++ b/src/cuda-sim/ptx_loader.cc @@ -38,7 +38,8 @@ /// extern prototypes -extern int ptx_error(yyscan_t yyscanner, const char *s); +extern int ptx_error(yyscan_t yyscanner, ptx_recognizer *recognizer, + const char *s); extern int ptx_lex_init(yyscan_t *scanner); extern void ptx_set_in(FILE *_in_str, yyscan_t yyscanner); extern int ptx_parse(yyscan_t scanner, ptx_recognizer *recognizer); diff --git a/src/cuda-sim/ptx_parser.cc b/src/cuda-sim/ptx_parser.cc index 3ae8de3..afdb41b 100644 --- a/src/cuda-sim/ptx_parser.cc +++ b/src/cuda-sim/ptx_parser.cc @@ -36,7 +36,8 @@ typedef void *yyscan_t; extern int ptx_get_lineno(yyscan_t yyscanner); extern YYSTYPE *ptx_get_lval(yyscan_t yyscanner); -extern int ptx_error(yyscan_t yyscanner, const char *s); +extern int ptx_error(yyscan_t yyscanner, ptx_recognizer *recognizer, + const char *s); extern int ptx_lex_init(yyscan_t *scanner); extern void ptx_set_in(FILE *_in_str, yyscan_t yyscanner); extern FILE *ptx_get_in(yyscan_t yyscanner); @@ -225,7 +226,7 @@ void ptx_recognizer::parse_error_impl(const char *file, unsigned line, g_error_detected = 1; printf("%s:%u: Parse error: %s (%s:%u)\n\n", gpgpu_ctx->g_filename, ptx_get_lineno(scanner), buf, file, line); - ptx_error(scanner, NULL); + ptx_error(scanner, this, NULL); abort(); exit(1); } @@ -624,8 +625,9 @@ void ptx_recognizer::add_scalar_type_spec(int type_spec) { parse_assert((g_opcode == -1) || (g_opcode == CVT_OP) || (g_opcode == SET_OP) || (g_opcode == SLCT_OP) || (g_opcode == TEX_OP) || (g_opcode == MMA_OP) || - (g_opcode == DP4A_OP), - "only cvt, set, slct, tex and dp4a can have more than one " + (g_opcode == DP4A_OP) || (g_opcode == VMIN_OP) || + (g_opcode == VMAX_OP), + "only cvt, set, slct, tex, vmin, vmax and dp4a can have more than one " "type specifier."); } g_scalar_type_spec = type_spec; diff --git a/src/gpgpu-sim/addrdec.cc b/src/gpgpu-sim/addrdec.cc index 655d790..19714ec 100644 --- a/src/gpgpu-sim/addrdec.cc +++ b/src/gpgpu-sim/addrdec.cc @@ -27,12 +27,16 @@ // POSSIBILITY OF SUCH DAMAGE. #include "addrdec.h" +#include <math.h> #include <string.h> #include "../option_parser.h" #include "gpu-sim.h" +#include "hashing.h" static long int powli(long int x, long int y); static unsigned int LOGB2_32(unsigned int v); +static unsigned next_powerOf2(unsigned n); + static new_addr_type addrdec_packbits(new_addr_type mask, new_addr_type val, unsigned char high, unsigned char low); static void addrdec_getmasklimit(new_addr_type mask, unsigned char *high, @@ -65,7 +69,8 @@ void linear_to_raw_address_translation::addrdec_setoption(option_parser_t opp) { "= new add. mask + flipped bank sel and chip sel bits", "0"); option_parser_register( - opp, "-memory_partition_indexing", OPT_UINT32, &memory_partition_indexing, + opp, "-gpgpu_memory_partition_indexing", OPT_UINT32, + &memory_partition_indexing, "0 = no indexing, 1 = bitwise xoring, 2 = IPoly, 3 = custom indexing", "0"); } @@ -89,7 +94,7 @@ new_addr_type linear_to_raw_address_translation::partition_address( void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, addrdec_t *tlx) const { - unsigned long long int addr_for_chip, rest_of_addr; + unsigned long long int addr_for_chip, rest_of_addr, rest_of_addr_high_bits; if (!gap) { tlx->chip = addrdec_packbits(addrdec_mask[CHIP], addr, addrdec_mkhigh[CHIP], addrdec_mklow[CHIP]); @@ -101,6 +106,9 @@ void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, addrdec_mklow[COL]); tlx->burst = addrdec_packbits(addrdec_mask[BURST], addr, addrdec_mkhigh[BURST], addrdec_mklow[BURST]); + rest_of_addr_high_bits = + (addr >> (ADDR_CHIP_S + (log2channel + log2sub_partition))); + } else { // Split the given address at ADDR_CHIP_S into (MSBs,LSBs) // - extract chip address using modulus of MSBs @@ -108,6 +116,7 @@ void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, // the LSBs addr_for_chip = (addr >> ADDR_CHIP_S) % m_n_channel; rest_of_addr = ((addr >> ADDR_CHIP_S) / m_n_channel) << ADDR_CHIP_S; + rest_of_addr_high_bits = ((addr >> ADDR_CHIP_S) / m_n_channel); rest_of_addr |= addr & ((1 << ADDR_CHIP_S) - 1); tlx->chip = addr_for_chip; @@ -127,68 +136,35 @@ void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, break; case BITWISE_PERMUTATION: { assert(!gap); - tlx->chip = (tlx->chip) ^ (tlx->row & (m_n_channel - 1)); + tlx->chip = + bitwise_hash_function(rest_of_addr_high_bits, tlx->chip, m_n_channel); assert(tlx->chip < m_n_channel); break; } case IPOLY: { - /* - * Set Indexing function from "Pseudo-randomly interleaved memory." - * Rau, B. R et al. - * ISCA 1991 - * - * equations are adopted from: - * "Sacat: streaming-aware conflict-avoiding thrashing-resistant gpgpu - * cache management scheme." Khairy et al. IEEE TPDS 2017. - */ - if (m_n_channel == 32) { - std::bitset<64> a(tlx->row); - std::bitset<5> chip(tlx->chip); - chip[0] = a[13] ^ a[12] ^ a[11] ^ a[10] ^ a[9] ^ a[6] ^ a[5] ^ a[3] ^ - a[0] ^ chip[0]; - chip[1] = a[14] ^ a[13] ^ a[12] ^ a[11] ^ a[10] ^ a[7] ^ a[6] ^ a[4] ^ - a[1] ^ chip[1]; - chip[2] = a[14] ^ a[10] ^ a[9] ^ a[8] ^ a[7] ^ a[6] ^ a[3] ^ a[2] ^ - a[0] ^ chip[2]; - chip[3] = - a[11] ^ a[10] ^ a[9] ^ a[8] ^ a[7] ^ a[4] ^ a[3] ^ a[1] ^ chip[3]; - chip[4] = - a[12] ^ a[11] ^ a[10] ^ a[9] ^ a[8] ^ a[5] ^ a[4] ^ a[2] ^ chip[4]; - tlx->chip = chip.to_ulong(); + // assert(!gap); + unsigned sub_partition_addr_mask = m_n_sub_partition_in_channel - 1; + unsigned sub_partition = tlx->chip * m_n_sub_partition_in_channel + + (tlx->bk & sub_partition_addr_mask); + sub_partition = ipoly_hash_function( + rest_of_addr_high_bits, sub_partition, + nextPowerOf2_m_n_channel * m_n_sub_partition_in_channel); - } else { /* Else incorrect number of channels for the hashing function */ - assert( - "\nGPGPU-Sim memory_partition_indexing error: The number of " - "channels should be " - "32 for the hashing IPOLY index function.\n" && - 0); - } - assert(tlx->chip < m_n_channel); - break; - } - case PAE: { - // Page Address Entropy - // random selected bits from the page and bank bits - // similar to - // Liu, Yuxi, et al. "Get Out of the Valley: Power-Efficient Address - // Mapping for GPUs." ISCA 2018 - std::bitset<64> a(tlx->row); - std::bitset<5> chip(tlx->chip); - std::bitset<4> b(tlx->bk); - chip[0] = a[13] ^ a[10] ^ a[9] ^ a[5] ^ a[0] ^ b[3] ^ b[0] ^ chip[0]; - chip[1] = a[12] ^ a[11] ^ a[6] ^ a[1] ^ b[3] ^ b[2] ^ b[1] ^ chip[1]; - chip[2] = a[14] ^ a[9] ^ a[8] ^ a[7] ^ a[2] ^ b[1] ^ chip[2]; - chip[3] = a[11] ^ a[10] ^ a[8] ^ a[3] ^ b[2] ^ b[3] ^ chip[3]; - chip[4] = a[12] ^ a[9] ^ a[8] ^ a[5] ^ a[4] ^ b[1] ^ b[0] ^ chip[4]; - tlx->chip = chip.to_ulong(); + if (gap) // if it is not 2^n partitions, then take modular + sub_partition = + sub_partition % (m_n_channel * m_n_sub_partition_in_channel); + + tlx->chip = sub_partition / m_n_sub_partition_in_channel; + tlx->sub_partition = sub_partition; assert(tlx->chip < m_n_channel); + assert(tlx->sub_partition < m_n_channel * m_n_sub_partition_in_channel); + return; break; } case RANDOM: { // This is an unrealistic hashing using software hashtable // we generate a random set for each memory address and save the value in - // a big hashtable for future reuse - new_addr_type chip_address = (addr >> ADDR_CHIP_S); + new_addr_type chip_address = (addr >> (ADDR_CHIP_S - log2sub_partition)); tr1_hash_map<new_addr_type, unsigned>::const_iterator got = address_random_interleaving.find(chip_address); if (got == address_random_interleaving.end()) { @@ -308,8 +284,12 @@ void linear_to_raw_address_translation::init( unsigned i; unsigned long long int mask; unsigned int nchipbits = ::LOGB2_32(n_channel); + log2channel = nchipbits; + log2sub_partition = ::LOGB2_32(n_sub_partition_in_channel); m_n_channel = n_channel; m_n_sub_partition_in_channel = n_sub_partition_in_channel; + nextPowerOf2_m_n_channel = ::next_powerOf2(n_channel); + m_n_sub_partition_total = n_channel * n_sub_partition_in_channel; gap = (n_channel - ::powli(2, nchipbits)); if (gap) { @@ -596,6 +576,22 @@ static unsigned int LOGB2_32(unsigned int v) { return r; } +// compute power of two greater than or equal to n +// https://www.techiedelight.com/round-next-highest-power-2/ +unsigned next_powerOf2(unsigned n) { + // decrement n (to handle the case when n itself + // is a power of 2) + n = n - 1; + + // do till only one bit is left + while (n & n - 1) n = n & (n - 1); // unset rightmost bit + + // n is now a power of two (less than n) + + // return next power of 2 + return n << 1; +} + static new_addr_type addrdec_packbits(new_addr_type mask, new_addr_type val, unsigned char high, unsigned char low) { unsigned pos = 0; diff --git a/src/gpgpu-sim/addrdec.h b/src/gpgpu-sim/addrdec.h index 03b84a4..d8db416 100644 --- a/src/gpgpu-sim/addrdec.h +++ b/src/gpgpu-sim/addrdec.h @@ -87,6 +87,10 @@ class linear_to_raw_address_translation { unsigned int gap; unsigned m_n_channel; int m_n_sub_partition_in_channel; + int m_n_sub_partition_total; + unsigned log2channel; + unsigned log2sub_partition; + unsigned nextPowerOf2_m_n_channel; }; #endif diff --git a/src/gpgpu-sim/dram.cc b/src/gpgpu-sim/dram.cc index 02356b2..ca47c46 100644 --- a/src/gpgpu-sim/dram.cc +++ b/src/gpgpu-sim/dram.cc @@ -31,6 +31,7 @@ #include "dram_sched.h" #include "gpu-misc.h" #include "gpu-sim.h" +#include "hashing.h" #include "l2cache.h" #include "mem_fetch.h" #include "mem_latency_stat.h" @@ -207,8 +208,18 @@ dram_req_t::dram_req_t(class mem_fetch *mf, unsigned banks, } case BITWISE_XORING_BK_INDEX: { // xoring bank bits with lower bits of the page - int lbank = log2(banks); - bk = tlx.bk ^ (tlx.row & ((1 << lbank) - 1)); + bk = bitwise_hash_function(tlx.row, tlx.bk, banks); + assert(bk < banks); + break; + } + case IPOLY_BK_INDEX: { + /*IPOLY for bank indexing function from "Pseudo-randomly interleaved + * memory." Rau, B. R et al. ISCA 1991 + * http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=348DEA37A3E440473B3C075EAABC63B6?doi=10.1.1.12.7149&rep=rep1&type=pdf + */ + // xoring bank bits with lower bits of the page + bk = ipoly_hash_function(tlx.row, tlx.bk, banks); + assert(bk < banks); break; } case CUSTOM_BK_INDEX: diff --git a/src/gpgpu-sim/dram.h b/src/gpgpu-sim/dram.h index 2e39a43..6c212e9 100644 --- a/src/gpgpu-sim/dram.h +++ b/src/gpgpu-sim/dram.h @@ -97,6 +97,7 @@ struct bank_t { enum bank_index_function { LINEAR_BK_INDEX = 0, BITWISE_XORING_BK_INDEX, + IPOLY_BK_INDEX, CUSTOM_BK_INDEX }; diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index eb95004..8f7ccd5 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -29,6 +29,7 @@ #include "gpu-cache.h" #include <assert.h> #include "gpu-sim.h" +#include "hashing.h" #include "stat-tool.h" // used to allocate memory that is large enough to adapt the changes in cache @@ -36,7 +37,7 @@ const char *cache_request_status_str(enum cache_request_status status) { static const char *static_cache_request_status_str[] = { - "HIT", "HIT_RESERVED", "MISS", "RESERVATION_FAIL", "SECTOR_MISS"}; + "HIT", "HIT_RESERVED", "MISS", "RESERVATION_FAIL", "SECTOR_MISS", "MSHR_HIT"}; assert(sizeof(static_cache_request_status_str) / sizeof(const char *) == NUM_CACHE_REQUEST_STATUS); @@ -62,24 +63,31 @@ unsigned l1d_cache_config::set_bank(new_addr_type addr) const { // For sector cache, we select one sector per bank (sector interleaving) // This is what was found in Volta (one sector per bank, sector interleaving) // otherwise, line interleaving - if (m_cache_type == SECTOR) - return (addr >> m_sector_sz_log2) & (l1_banks - 1); - else - return (addr >> m_line_sz_log2) & (l1_banks - 1); + return cache_config::hash_function(addr, l1_banks, l1_banks_byte_interleaving, + m_l1_banks_log2, + l1_banks_hashing_function); +} + +unsigned cache_config::set_index(new_addr_type addr) const { + return cache_config::hash_function(addr, m_nset, m_line_sz_log2, m_nset_log2, + m_set_index_function); } -unsigned l1d_cache_config::set_index(new_addr_type addr) const { - unsigned set_index = m_nset; // Default to linear set index function - unsigned lower_xor = 0; - unsigned upper_xor = 0; +unsigned cache_config::hash_function(new_addr_type addr, unsigned m_nset, + unsigned m_line_sz_log2, + unsigned m_nset_log2, + unsigned m_index_function) const { + unsigned set_index = 0; - switch (m_set_index_function) { - case FERMI_HASH_SET_FUNCTION: - case BITWISE_XORING_FUNCTION: + switch (m_index_function) { + case FERMI_HASH_SET_FUNCTION: { /* * Set Indexing function from "A Detailed GPU Cache Model Based on Reuse * Distance Theory" Cedric Nugteren et al. HPCA 2014 */ + unsigned lower_xor = 0; + unsigned upper_xor = 0; + if (m_nset == 32 || m_nset == 64) { // Lower xor value is bits 7-11 lower_xor = (addr >> m_line_sz_log2) & 0x1F; @@ -102,54 +110,34 @@ unsigned l1d_cache_config::set_index(new_addr_type addr) const { 0); } break; + } - case HASH_IPOLY_FUNCTION: - /* - * Set Indexing function from "Pseudo-randomly interleaved memory." - * Rau, B. R et al. - * ISCA 1991 - * - * "Sacat: streaming-aware conflict-avoiding thrashing-resistant gpgpu - * cache management scheme." Khairy et al. IEEE TPDS 2017. - */ - if (m_nset == 32 || m_nset == 64) { - std::bitset<64> a(addr); - std::bitset<6> index; - index[0] = a[25] ^ a[24] ^ a[23] ^ a[22] ^ a[21] ^ a[18] ^ a[17] ^ - a[15] ^ a[12] ^ a[7]; // 10 - index[1] = a[26] ^ a[25] ^ a[24] ^ a[23] ^ a[22] ^ a[19] ^ a[18] ^ - a[16] ^ a[13] ^ a[8]; // 10 - index[2] = a[26] ^ a[22] ^ a[21] ^ a[20] ^ a[19] ^ a[18] ^ a[15] ^ - a[14] ^ a[12] ^ a[9]; // 10 - index[3] = a[23] ^ a[22] ^ a[21] ^ a[20] ^ a[19] ^ a[16] ^ a[15] ^ - a[13] ^ a[10]; // 9 - index[4] = a[24] ^ a[23] ^ a[22] ^ a[21] ^ a[20] ^ a[17] ^ a[16] ^ - a[14] ^ a[11]; // 9 - - if (m_nset == 64) index[5] = a[12]; - - set_index = index.to_ulong(); - - } else { /* Else incorrect number of sets for the hashing function */ - assert( - "\nGPGPU-Sim cache configuration error: The number of sets should " - "be " - "32 or 64 for the hashing set index function.\n" && - 0); - } + case BITWISE_XORING_FUNCTION: { + new_addr_type higher_bits = addr >> (m_line_sz_log2 + m_nset_log2); + unsigned index = (addr >> m_line_sz_log2) & (m_nset - 1); + set_index = bitwise_hash_function(higher_bits, index, m_nset); break; - - case CUSTOM_SET_FUNCTION: + } + case HASH_IPOLY_FUNCTION: { + new_addr_type higher_bits = addr >> (m_line_sz_log2 + m_nset_log2); + unsigned index = (addr >> m_line_sz_log2) & (m_nset - 1); + set_index = ipoly_hash_function(higher_bits, index, m_nset); + break; + } + case CUSTOM_SET_FUNCTION: { /* No custom set function implemented */ break; + } - case LINEAR_SET_FUNCTION: + case LINEAR_SET_FUNCTION: { set_index = (addr >> m_line_sz_log2) & (m_nset - 1); break; + } - default: + default: { assert("\nUndefined set index function.\n" && 0); break; + } } // Linear function selected or custom set index function not implemented @@ -166,13 +154,14 @@ void l2_cache_config::init(linear_to_raw_address_translation *address_mapping) { } unsigned l2_cache_config::set_index(new_addr_type addr) const { - if (!m_address_mapping) { - return (addr >> m_line_sz_log2) & (m_nset - 1); - } else { + new_addr_type part_addr = addr; + + if (m_address_mapping) { // Calculate set index without memory partition bits to reduce set camping - new_addr_type part_addr = m_address_mapping->partition_address(addr); - return (part_addr >> m_line_sz_log2) & (m_nset - 1); + part_addr = m_address_mapping->partition_address(addr); } + + return cache_config::set_index(part_addr); } tag_array::~tag_array() { @@ -1136,6 +1125,7 @@ void baseline_cache::send_read_request(new_addr_type addr, m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf); m_mshrs.add(mshr_addr, mf); + m_stats.inc_stats(mf->get_access_type(), MSHR_HIT); do_miss = true; } else if (!mshr_hit && mshr_avail && @@ -1317,6 +1307,10 @@ enum cache_request_status data_cache::wr_miss_wa_naive( mem_fetch *wb = m_memfetch_creator->alloc( evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle); + // the evicted block may have wrong chip id when advanced L2 hashing is + // used, so set the right chip address from the original mf + wb->set_chip(mf->get_tlx_addr().chip); + wb->set_parition(mf->get_tlx_addr().sub_partition); send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events); } @@ -1360,6 +1354,10 @@ enum cache_request_status data_cache::wr_miss_wa_fetch_on_write( mem_fetch *wb = m_memfetch_creator->alloc( evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle); + // the evicted block may have wrong chip id when advanced L2 hashing is + // used, so set the right chip address from the original mf + wb->set_chip(mf->get_tlx_addr().chip); + wb->set_parition(mf->get_tlx_addr().sub_partition); send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events); } @@ -1426,6 +1424,10 @@ enum cache_request_status data_cache::wr_miss_wa_fetch_on_write( mem_fetch *wb = m_memfetch_creator->alloc( evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle); + // the evicted block may have wrong chip id when advanced L2 hashing is + // used, so set the right chip address from the original mf + wb->set_chip(mf->get_tlx_addr().chip); + wb->set_parition(mf->get_tlx_addr().sub_partition); send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events); } @@ -1456,16 +1458,19 @@ enum cache_request_status data_cache::wr_miss_wa_lazy_fetch_on_read( m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf); assert(m_status != HIT); cache_block_t *block = m_tag_array->get_block(cache_index); - block->set_status(MODIFIED, mf->get_access_sector_mask()); if (m_status == HIT_RESERVED) { block->set_ignore_on_fill(true, mf->get_access_sector_mask()); block->set_modified_on_fill(true, mf->get_access_sector_mask()); + } else { + block->set_status(MODIFIED, mf->get_access_sector_mask()); } if (mf->get_access_byte_mask().count() == m_config.get_atom_sz()) { block->set_m_readable(true, mf->get_access_sector_mask()); } else { block->set_m_readable(false, mf->get_access_sector_mask()); + if (m_status == HIT_RESERVED) + block->set_readable_on_fill(true, mf->get_access_sector_mask()); } if (m_status != RESERVATION_FAIL) { @@ -1475,6 +1480,10 @@ enum cache_request_status data_cache::wr_miss_wa_lazy_fetch_on_read( mem_fetch *wb = m_memfetch_creator->alloc( evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle); + // the evicted block may have wrong chip id when advanced L2 hashing is + // used, so set the right chip address from the original mf + wb->set_chip(mf->get_tlx_addr().chip); + wb->set_parition(mf->get_tlx_addr().sub_partition); send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events); } @@ -1547,6 +1556,10 @@ enum cache_request_status data_cache::rd_miss_base( mem_fetch *wb = m_memfetch_creator->alloc( evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle); + // the evicted block may have wrong chip id when advanced L2 hashing is + // used, so set the right chip address from the original mf + wb->set_chip(mf->get_tlx_addr().chip); + wb->set_parition(mf->get_tlx_addr().sub_partition); send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events); } return MISS; diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h index 2a37876..26369c3 100644 --- a/src/gpgpu-sim/gpu-cache.h +++ b/src/gpgpu-sim/gpu-cache.h @@ -49,6 +49,7 @@ enum cache_request_status { MISS, RESERVATION_FAIL, SECTOR_MISS, + MSHR_HIT, NUM_CACHE_REQUEST_STATUS }; @@ -128,6 +129,8 @@ struct cache_block_t { mem_access_sector_mask_t sector_mask) = 0; virtual void set_modified_on_fill(bool m_modified, mem_access_sector_mask_t sector_mask) = 0; + virtual void set_readable_on_fill(bool readable, + mem_access_sector_mask_t sector_mask) = 0; virtual unsigned get_modified_size() = 0; virtual void set_m_readable(bool readable, mem_access_sector_mask_t sector_mask) = 0; @@ -147,6 +150,7 @@ struct line_cache_block : public cache_block_t { m_status = INVALID; m_ignore_on_fill_status = false; m_set_modified_on_fill = false; + m_set_readable_on_fill = false; m_readable = true; } void allocate(new_addr_type tag, new_addr_type block_addr, unsigned time, @@ -159,12 +163,16 @@ struct line_cache_block : public cache_block_t { m_status = RESERVED; m_ignore_on_fill_status = false; m_set_modified_on_fill = false; + m_set_readable_on_fill = false; } void fill(unsigned time, mem_access_sector_mask_t sector_mask) { // if(!m_ignore_on_fill_status) // assert( m_status == RESERVED ); m_status = m_set_modified_on_fill ? MODIFIED : VALID; + + if (m_set_readable_on_fill) + m_readable = true; m_fill_time = time; } @@ -197,6 +205,10 @@ struct line_cache_block : public cache_block_t { mem_access_sector_mask_t sector_mask) { m_set_modified_on_fill = m_modified; } + virtual void set_readable_on_fill(bool readable, + mem_access_sector_mask_t sector_mask) { + m_set_readable_on_fill = readable; + } virtual unsigned get_modified_size() { return SECTOR_CHUNCK_SIZE * SECTOR_SIZE; // i.e. cache line size } @@ -218,6 +230,7 @@ struct line_cache_block : public cache_block_t { cache_block_state m_status; bool m_ignore_on_fill_status; bool m_set_modified_on_fill; + bool m_set_readable_on_fill; bool m_readable; }; @@ -232,6 +245,7 @@ struct sector_cache_block : public cache_block_t { m_status[i] = INVALID; m_ignore_on_fill_status[i] = false; m_set_modified_on_fill[i] = false; + m_set_readable_on_fill[i] = false; m_readable[i] = true; } m_line_alloc_time = 0; @@ -261,6 +275,7 @@ struct sector_cache_block : public cache_block_t { m_status[sidx] = RESERVED; m_ignore_on_fill_status[sidx] = false; m_set_modified_on_fill[sidx] = false; + m_set_readable_on_fill[sidx] = false; // set line stats m_line_alloc_time = time; // only set this for the first allocated sector @@ -283,6 +298,8 @@ struct sector_cache_block : public cache_block_t { else m_set_modified_on_fill[sidx] = false; + m_set_readable_on_fill[sidx] = false; + m_status[sidx] = RESERVED; m_ignore_on_fill_status[sidx] = false; // m_set_modified_on_fill[sidx] = false; @@ -300,6 +317,11 @@ struct sector_cache_block : public cache_block_t { // assert( m_status[sidx] == RESERVED ); m_status[sidx] = m_set_modified_on_fill[sidx] ? MODIFIED : VALID; + + if (m_set_readable_on_fill[sidx]) { + m_readable[sidx] = true; + m_set_readable_on_fill[sidx] = false; + } m_sector_fill_time[sidx] = time; m_line_fill_time = time; @@ -366,6 +388,11 @@ struct sector_cache_block : public cache_block_t { m_set_modified_on_fill[sidx] = m_modified; } + virtual void set_readable_on_fill(bool readable, + mem_access_sector_mask_t sector_mask) { + unsigned sidx = get_sector_index(sector_mask); + m_set_readable_on_fill[sidx] = readable; + } virtual void set_m_readable(bool readable, mem_access_sector_mask_t sector_mask) { unsigned sidx = get_sector_index(sector_mask); @@ -400,6 +427,7 @@ struct sector_cache_block : public cache_block_t { cache_block_state m_status[SECTOR_CHUNCK_SIZE]; bool m_ignore_on_fill_status[SECTOR_CHUNCK_SIZE]; bool m_set_modified_on_fill[SECTOR_CHUNCK_SIZE]; + bool m_set_readable_on_fill[SECTOR_CHUNCK_SIZE]; bool m_readable[SECTOR_CHUNCK_SIZE]; unsigned get_sector_index(mem_access_sector_mask_t sector_mask) { @@ -686,17 +714,11 @@ class cache_config { m_line_sz * m_nset * m_assoc, m_nset, m_assoc, m_line_sz); } - virtual unsigned set_index(new_addr_type addr) const { - if (m_set_index_function != LINEAR_SET_FUNCTION) { - printf( - "\nGPGPU-Sim cache configuration error: Hashing or " - "custom set index function selected in configuration " - "file for a cache that has not overloaded the set_index " - "function\n"); - abort(); - } - return (addr >> m_line_sz_log2) & (m_nset - 1); - } + virtual unsigned set_index(new_addr_type addr) const; + + unsigned hash_function(new_addr_type addr, unsigned m_nset, + unsigned m_line_sz_log2, unsigned m_nset_log2, + unsigned m_index_function) const; new_addr_type tag(new_addr_type addr) const { // For generality, the tag includes both index and tag. This allows for more @@ -793,10 +815,18 @@ class cache_config { class l1d_cache_config : public cache_config { public: l1d_cache_config() : cache_config() {} - virtual unsigned set_index(new_addr_type addr) const; unsigned set_bank(new_addr_type addr) const; + void init(char *config, FuncCache status) { + m_banks_byte_interleaving_log2 = LOGB2(l1_banks_byte_interleaving); + m_l1_banks_log2 = LOGB2(l1_banks); + cache_config::init(config, status); + } unsigned l1_latency; unsigned l1_banks; + unsigned m_l1_banks_log2; + unsigned l1_banks_byte_interleaving; + unsigned m_banks_byte_interleaving_log2; + unsigned l1_banks_hashing_function; }; class l2_cache_config : public cache_config { diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index a6a39ab..1650688 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -129,9 +129,10 @@ void power_config::reg_options(class OptionParser *opp) { } void memory_config::reg_options(class OptionParser *opp) { - option_parser_register(opp, "-perf_sim_memcpy", OPT_BOOL, &m_perf_sim_memcpy, - "Fill the L2 cache on memcpy", "1"); - option_parser_register(opp, "-simple_dram_model", OPT_BOOL, + option_parser_register(opp, "-gpgpu_perf_sim_memcpy", OPT_BOOL, + &m_perf_sim_memcpy, "Fill the L2 cache on memcpy", + "1"); + option_parser_register(opp, "-gpgpu_simple_dram_model", OPT_BOOL, &simple_dram_model, "simple_dram_model with fixed latency and BW", "0"); option_parser_register(opp, "-gpgpu_dram_scheduler", OPT_INT32, @@ -187,11 +188,11 @@ void memory_config::reg_options(class OptionParser *opp) { "DRAM timing parameters = " "{nbk:tCCD:tRRD:tRCD:tRAS:tRP:tRC:CL:WL:tCDLR:tWR:nbkgrp:tCCDL:tRTPL}", "4:2:8:12:21:13:34:9:4:5:13:1:0:0"); - option_parser_register(opp, "-rop_latency", OPT_UINT32, &rop_latency, + option_parser_register(opp, "-gpgpu_l2_rop_latency", OPT_UINT32, &rop_latency, "ROP queue latency (default 85)", "85"); option_parser_register(opp, "-dram_latency", OPT_UINT32, &dram_latency, "DRAM latency (default 30)", "30"); - option_parser_register(opp, "-dual_bus_interface", OPT_UINT32, + option_parser_register(opp, "-dram_dual_bus_interface", OPT_UINT32, &dual_bus_interface, "dual_bus_interface (default = 0) ", "0"); option_parser_register(opp, "-dram_bnk_indexing_policy", OPT_UINT32, @@ -204,13 +205,13 @@ void memory_config::reg_options(class OptionParser *opp) { "dram_bnkgrp_indexing_policy (0 = take higher bits, 1 " "= take lower bits) (Default = 0)", "0"); - option_parser_register(opp, "-Seperate_Write_Queue_Enable", OPT_BOOL, + option_parser_register(opp, "-dram_seperate_write_queue_enable", OPT_BOOL, &seperate_write_queue_enabled, "Seperate_Write_Queue_Enable", "0"); - option_parser_register(opp, "-Write_Queue_Size", OPT_CSTR, + option_parser_register(opp, "-dram_write_queue_size", OPT_CSTR, &write_queue_size_opt, "Write_Queue_Size", "32:28:16"); option_parser_register( - opp, "-Elimnate_rw_turnaround", OPT_BOOL, &elimnate_rw_turnaround, + opp, "-dram_elimnate_rw_turnaround", OPT_BOOL, &elimnate_rw_turnaround, "elimnate_rw_turnaround i.e set tWTR and tRTW = 0", "0"); option_parser_register(opp, "-icnt_flit_size", OPT_UINT32, &icnt_flit_size, "icnt_flit_size", "32"); @@ -248,11 +249,18 @@ void shader_core_config::reg_options(class OptionParser *opp) { " {<nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_" "alloc>,<mshr>:<N>:<merge>,<mq> | none}", "none"); - option_parser_register(opp, "-l1_banks", OPT_UINT32, &m_L1D_config.l1_banks, - "The number of L1 cache banks", "1"); - option_parser_register(opp, "-l1_latency", OPT_UINT32, + option_parser_register(opp, "-gpgpu_l1_banks", OPT_UINT32, + &m_L1D_config.l1_banks, "The number of L1 cache banks", + "1"); + option_parser_register(opp, "-gpgpu_l1_banks_byte_interleaving", OPT_UINT32, + &m_L1D_config.l1_banks_byte_interleaving, + "l1 banks byte interleaving granularity", "32"); + option_parser_register(opp, "-gpgpu_l1_banks_hashing_function", OPT_UINT32, + &m_L1D_config.l1_banks_hashing_function, + "l1 banks hashing function", "0"); + option_parser_register(opp, "-gpgpu_l1_latency", OPT_UINT32, &m_L1D_config.l1_latency, "L1 Hit Latency", "1"); - option_parser_register(opp, "-smem_latency", OPT_UINT32, &smem_latency, + option_parser_register(opp, "-gpgpu_smem_latency", OPT_UINT32, &smem_latency, "smem Latency", "3"); option_parser_register(opp, "-gpgpu_cache:dl1PrefL1", OPT_CSTR, &m_L1D_config.m_config_stringPrefL1, @@ -266,7 +274,7 @@ void shader_core_config::reg_options(class OptionParser *opp) { " {<nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_" "alloc>,<mshr>:<N>:<merge>,<mq> | none}", "none"); - option_parser_register(opp, "-gmem_skip_L1D", OPT_BOOL, &gmem_skip_L1D, + option_parser_register(opp, "-gpgpu_gmem_skip_L1D", OPT_BOOL, &gmem_skip_L1D, "global memory access skip L1D cache (implements " "-Xptxas -dlcm=cg, default=no skip)", "0"); @@ -318,7 +326,7 @@ void shader_core_config::reg_options(class OptionParser *opp) { option_parser_register( opp, "-gpgpu_shmem_size", OPT_UINT32, &gpgpu_shmem_size, "Size of shared memory per shader core (default 16kB)", "16384"); - option_parser_register(opp, "-adaptive_cache_config", OPT_BOOL, + option_parser_register(opp, "-gpgpu_adaptive_cache_config", OPT_UINT32, &adaptive_cache_config, "adaptive_cache_config", "0"); option_parser_register( opp, "-gpgpu_shmem_sizeDefault", OPT_UINT32, &gpgpu_shmem_sizeDefault, @@ -343,7 +351,7 @@ void shader_core_config::reg_options(class OptionParser *opp) { "memory bank conflict check ", "2"); option_parser_register( - opp, "-mem_unit_ports", OPT_INT32, &mem_unit_ports, + opp, "-gpgpu_mem_unit_ports", OPT_INT32, &mem_unit_ports, "The number of memory transactions allowed per core cycle", "1"); option_parser_register(opp, "-gpgpu_shmem_warp_parts", OPT_INT32, &mem_warp_parts, @@ -369,10 +377,11 @@ void shader_core_config::reg_options(class OptionParser *opp) { option_parser_register( opp, "-gpgpu_reg_bank_use_warp_id", OPT_BOOL, &gpgpu_reg_bank_use_warp_id, "Use warp ID in mapping registers to banks (default = off)", "0"); - option_parser_register(opp, "-sub_core_model", OPT_BOOL, &sub_core_model, + option_parser_register(opp, "-gpgpu_sub_core_model", OPT_BOOL, + &sub_core_model, "Sub Core Volta/Pascal model (default = off)", "0"); - option_parser_register(opp, "-enable_specialized_operand_collector", OPT_BOOL, - &enable_specialized_operand_collector, + option_parser_register(opp, "-gpgpu_enable_specialized_operand_collector", + OPT_BOOL, &enable_specialized_operand_collector, "enable_specialized_operand_collector", "1"); option_parser_register(opp, "-gpgpu_operand_collector_num_units_sp", OPT_INT32, &gpgpu_operand_collector_num_units_sp, @@ -496,7 +505,7 @@ void shader_core_config::reg_options(class OptionParser *opp) { "1"); option_parser_register(opp, "-gpgpu_num_tensor_core_units", OPT_INT32, &gpgpu_num_tensor_core_units, - "Number of tensor_core units (default=1)", "1"); + "Number of tensor_core units (default=1)", "0"); option_parser_register( opp, "-gpgpu_num_mem_units", OPT_INT32, &gpgpu_num_mem_units, "Number if ldst units (default=1) WARNING: not hooked up to anything", @@ -515,6 +524,28 @@ void shader_core_config::reg_options(class OptionParser *opp) { option_parser_register( opp, "-gpgpu_concurrent_kernel_sm", OPT_BOOL, &gpgpu_concurrent_kernel_sm, "Support concurrent kernels on a SM (default = disabled)", "0"); + option_parser_register(opp, "-gpgpu_perfect_inst_const_cache", OPT_BOOL, + &perfect_inst_const_cache, + "perfect inst and const cache mode, so all inst and " + "const hits in the cache(default = disabled)", + "0"); + option_parser_register( + opp, "-gpgpu_inst_fetch_throughput", OPT_INT32, &inst_fetch_throughput, + "the number of fetched intruction per warp each cycle", "1"); + option_parser_register(opp, "-gpgpu_reg_file_port_throughput", OPT_INT32, + ®_file_port_throughput, + "the number ports of the register file", "1"); + + for (unsigned j = 0; j < SPECIALIZED_UNIT_NUM; ++j) { + std::stringstream ss; + ss << "-specialized_unit_" << j + 1; + option_parser_register(opp, ss.str().c_str(), OPT_CSTR, + &specialized_unit_string[j], + "specialized unit config" + " {<enabled>,<num_units>:<latency>:<initiation>,<ID_" + "OC_SPEC>:<OC_EX_SPEC>,<NAME>}", + "0,4,4,4,4,BRA"); + } } void gpgpu_sim_config::reg_options(option_parser_t opp) { @@ -620,6 +651,11 @@ void gpgpu_sim_config::reg_options(option_parser_t opp) { option_parser_register(opp, "-gpgpu_cdp_enabled", OPT_BOOL, &(gpgpu_ctx->device_runtime->g_cdp_enabled), "Turn on CDP", "0"); + + option_parser_register(opp, "-gpgpu_TB_launch_latency", OPT_INT32, + &(gpgpu_ctx->device_runtime->g_TB_launch_latency), + "thread block launch latency in cycles. Default: 0", + "0"); } ///////////////////////////////////////////////////////////////////////////// @@ -696,9 +732,17 @@ bool gpgpu_sim::get_more_cta_left() const { return false; } +void gpgpu_sim::decrement_kernel_latency() { + for (unsigned n = 0; n < m_running_kernels.size(); n++) { + if (m_running_kernels[n] && m_running_kernels[n]->m_kernel_TB_latency) + m_running_kernels[n]->m_kernel_TB_latency--; + } +} + kernel_info_t *gpgpu_sim::select_kernel() { if (m_running_kernels[m_last_issued_kernel] && - !m_running_kernels[m_last_issued_kernel]->no_more_ctas_to_run()) { + !m_running_kernels[m_last_issued_kernel]->no_more_ctas_to_run() && + !m_running_kernels[m_last_issued_kernel]->m_kernel_TB_latency) { unsigned launch_uid = m_running_kernels[m_last_issued_kernel]->get_uid(); if (std::find(m_executed_kernel_uids.begin(), m_executed_kernel_uids.end(), launch_uid) == m_executed_kernel_uids.end()) { @@ -714,7 +758,8 @@ kernel_info_t *gpgpu_sim::select_kernel() { for (unsigned n = 0; n < m_running_kernels.size(); n++) { unsigned idx = (n + m_last_issued_kernel + 1) % m_config.max_concurrent_kernel; - if (kernel_more_cta_left(m_running_kernels[idx])) { + if (kernel_more_cta_left(m_running_kernels[idx]) && + !m_running_kernels[idx]->m_kernel_TB_latency) { m_last_issued_kernel = idx; m_running_kernels[idx]->start_cycle = gpu_sim_cycle + gpu_tot_sim_cycle; // record this kernel for stat print if it is the first time this kernel @@ -763,6 +808,14 @@ void gpgpu_sim::stop_all_running_kernels() { } } +void exec_gpgpu_sim::createSIMTCluster() { + m_cluster = new simt_core_cluster *[m_shader_config->n_simt_clusters]; + for (unsigned i = 0; i < m_shader_config->n_simt_clusters; i++) + m_cluster[i] = + new exec_simt_core_cluster(this, i, m_shader_config, m_memory_config, + m_shader_stats, m_memory_stats); +} + gpgpu_sim::gpgpu_sim(const gpgpu_sim_config &config, gpgpu_context *ctx) : gpgpu_t(config, ctx), m_config(config) { gpgpu_ctx = ctx; @@ -803,12 +856,6 @@ gpgpu_sim::gpgpu_sim(const gpgpu_sim_config &config, gpgpu_context *ctx) partiton_replys_in_parallel = 0; partiton_replys_in_parallel_total = 0; - m_cluster = new simt_core_cluster *[m_shader_config->n_simt_clusters]; - for (unsigned i = 0; i < m_shader_config->n_simt_clusters; i++) - m_cluster[i] = - new simt_core_cluster(this, i, m_shader_config, m_memory_config, - m_shader_stats, m_memory_stats); - m_memory_partition_unit = new memory_partition_unit *[m_memory_config->m_n_mem]; m_memory_sub_partition = @@ -1518,6 +1565,14 @@ void shader_core_ctx::release_shader_resource_1block(unsigned hw_ctaid, * object that tells us which kernel to ask for a CTA from */ +unsigned exec_shader_core_ctx::sim_init_thread( + kernel_info_t &kernel, ptx_thread_info **thread_info, int sid, unsigned tid, + unsigned threads_left, unsigned num_threads, core_t *core, + unsigned hw_cta_id, unsigned hw_warp_id, gpgpu_t *gpu) { + return ptx_sim_init_thread(kernel, thread_info, sid, tid, threads_left, + num_threads, core, hw_cta_id, hw_warp_id, gpu); +} + void shader_core_ctx::issue_block2core(kernel_info_t &kernel) { if (!m_config->gpgpu_concurrent_kernel_sm) set_max_cta(kernel); @@ -1583,7 +1638,7 @@ void shader_core_ctx::issue_block2core(kernel_info_t &kernel) { for (unsigned i = start_thread; i < end_thread; i++) { m_threadState[i].m_cta_id = free_cta_hw_id; unsigned warp_id = i / m_config->warp_size; - nthreads_in_block += ptx_sim_init_thread( + nthreads_in_block += sim_init_thread( kernel, &m_thread[i], m_sid, i, cta_size - (i - start_thread), m_config->n_thread_per_shader, this, free_cta_hw_id, warp_id, m_cluster->get_gpu()); @@ -1621,8 +1676,7 @@ void shader_core_ctx::issue_block2core(kernel_info_t &kernel) { m_barriers.allocate_barrier(free_cta_hw_id, warps); // initialize the SIMT stacks and fetch hardware - init_warps(free_cta_hw_id, start_thread, end_thread, ctaid, cta_size, - kernel.get_uid()); + init_warps(free_cta_hw_id, start_thread, end_thread, ctaid, cta_size, kernel); m_n_active_cta++; shader_CTA_count_log(m_sid, 1); @@ -1814,6 +1868,7 @@ void gpgpu_sim::cycle() { #endif issue_block2core(); + decrement_kernel_latency(); // Depending on configuration, invalidate the caches once all of threads are // completed. @@ -1921,12 +1976,15 @@ void shader_core_ctx::dump_warp_state(FILE *fout) const { fprintf(fout, "\n"); fprintf(fout, "per warp functional simulation status:\n"); for (unsigned w = 0; w < m_config->max_warps_per_shader; w++) - m_warp[w].print(fout); + m_warp[w]->print(fout); } void gpgpu_sim::perf_memcpy_to_gpu(size_t dst_start_addr, size_t count) { if (m_memory_config->m_perf_sim_memcpy) { - assert(dst_start_addr % 32 == 0); + // if(!m_config.trace_driven_mode) //in trace-driven mode, CUDA runtime + // can start nre data structure at any position assert (dst_start_addr % + // 32 + //== 0); for (unsigned counter = 0; counter < count; counter += 32) { const unsigned wr_addr = dst_start_addr + counter; diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index 19fbf5d..2e6820d 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -370,6 +370,8 @@ class gpgpu_sim_config : public power_config, return runtime_pending_launch_count_limit; } + bool flush_l1() const { return gpgpu_flush_l1_cache; } + private: void init_clock_domains(void); @@ -525,6 +527,7 @@ class gpgpu_sim : public gpgpu_t { bool kernel_more_cta_left(kernel_info_t *kernel) const; bool hit_max_cta_count() const; kernel_info_t *select_kernel(); + void decrement_kernel_latency(); const gpgpu_sim_config &get_config() const { return m_config; } void gpu_print_stat(); @@ -577,8 +580,8 @@ class gpgpu_sim : public gpgpu_t { void gpgpu_debug(); + protected: ///// data ///// - class simt_core_cluster **m_cluster; class memory_partition_unit **m_memory_partition_unit; class memory_sub_partition **m_memory_sub_partition; @@ -633,6 +636,7 @@ class gpgpu_sim : public gpgpu_t { // into a string for stat printout void clear_executed_kernel_info(); //< clear the kernel information after // stat printout + virtual void createSIMTCluster() = 0; public: unsigned long long gpu_sim_insn; @@ -681,4 +685,14 @@ class gpgpu_sim : public gpgpu_t { } }; +class exec_gpgpu_sim : public gpgpu_sim { + public: + exec_gpgpu_sim(const gpgpu_sim_config &config, gpgpu_context *ctx) + : gpgpu_sim(config, ctx) { + createSIMTCluster(); + } + + virtual void createSIMTCluster(); +}; + #endif diff --git a/src/gpgpu-sim/hashing.cc b/src/gpgpu-sim/hashing.cc new file mode 100644 index 0000000..f566aa4 --- /dev/null +++ b/src/gpgpu-sim/hashing.cc @@ -0,0 +1,125 @@ +// author: Mahmoud Khairy, (Purdue Univ) +// email: [email protected] + +#include <math.h> +#include <string.h> +#include "../abstract_hardware_model.h" +#include "gpu-cache.h" + +unsigned ipoly_hash_function(new_addr_type higher_bits, unsigned index, + unsigned bank_set_num) { + /* + * Set Indexing function from "Pseudo-randomly interleaved memory." + * Rau, B. R et al. + * ISCA 1991 + * http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=348DEA37A3E440473B3C075EAABC63B6?doi=10.1.1.12.7149&rep=rep1&type=pdf + * + * equations are corresponding to IPOLY(37) and are adopted from: + * "Sacat: streaming-aware conflict-avoiding thrashing-resistant gpgpu + * cache management scheme." Khairy et al. IEEE TPDS 2017. + * + * equations for 16 banks are corresponding to IPOLY(5) + * equations for 32 banks are corresponding to IPOLY(37) + * equations for 64 banks are corresponding to IPOLY(67) + * To see all the IPOLY equations for all the degrees, see + * http://wireless-systems.ece.gatech.edu/6604/handouts/Peterson's%20Table.pdf + * + * We generate these equations using GF(2) arithmetic: + * http://www.ee.unb.ca/cgi-bin/tervo/calc.pl?num=&den=&f=d&e=1&m=1 + * + * We go through all the strides 128 (10000000), 256 (100000000),... and + * do modular arithmetic in GF(2) Then, we create the H-matrix and group + * each bit together, for more info read the ISCA 1991 paper + * + * IPOLY hashing guarantees conflict-free for all 2^n strides which widely + * exit in GPGPU applications and also show good performance for other + * strides. + */ + if (bank_set_num == 16) { + std::bitset<64> a(higher_bits); + std::bitset<4> b(index); + std::bitset<4> new_index(index); + + new_index[0] = + a[11] ^ a[10] ^ a[9] ^ a[8] ^ a[6] ^ a[4] ^ a[3] ^ a[0] ^ b[0]; + new_index[1] = + a[12] ^ a[8] ^ a[7] ^ a[6] ^ a[5] ^ a[3] ^ a[1] ^ a[0] ^ b[1]; + new_index[2] = a[9] ^ a[8] ^ a[7] ^ a[6] ^ a[4] ^ a[2] ^ a[1] ^ b[2]; + new_index[3] = a[10] ^ a[9] ^ a[8] ^ a[7] ^ a[5] ^ a[3] ^ a[2] ^ b[3]; + + return new_index.to_ulong(); + + } else if (bank_set_num == 32) { + std::bitset<64> a(higher_bits); + std::bitset<5> b(index); + std::bitset<5> new_index(index); + + new_index[0] = + a[13] ^ a[12] ^ a[11] ^ a[10] ^ a[9] ^ a[6] ^ a[5] ^ a[3] ^ a[0] ^ b[0]; + new_index[1] = a[14] ^ a[13] ^ a[12] ^ a[11] ^ a[10] ^ a[7] ^ a[6] ^ a[4] ^ + a[1] ^ b[1]; + new_index[2] = + a[14] ^ a[10] ^ a[9] ^ a[8] ^ a[7] ^ a[6] ^ a[3] ^ a[2] ^ a[0] ^ b[2]; + new_index[3] = + a[11] ^ a[10] ^ a[9] ^ a[8] ^ a[7] ^ a[4] ^ a[3] ^ a[1] ^ b[3]; + new_index[4] = + a[12] ^ a[11] ^ a[10] ^ a[9] ^ a[8] ^ a[5] ^ a[4] ^ a[2] ^ b[4]; + return new_index.to_ulong(); + + } else if (bank_set_num == 64) { + std::bitset<64> a(higher_bits); + std::bitset<6> b(index); + std::bitset<6> new_index(index); + + new_index[0] = a[18] ^ a[17] ^ a[16] ^ a[15] ^ a[12] ^ a[10] ^ a[6] ^ a[5] ^ + a[0] ^ b[0]; + new_index[1] = a[15] ^ a[13] ^ a[12] ^ a[11] ^ a[10] ^ a[7] ^ a[5] ^ a[1] ^ + a[0] ^ b[1]; + new_index[2] = a[16] ^ a[14] ^ a[13] ^ a[12] ^ a[11] ^ a[8] ^ a[6] ^ a[2] ^ + a[1] ^ b[2]; + new_index[3] = a[17] ^ a[15] ^ a[14] ^ a[13] ^ a[12] ^ a[9] ^ a[7] ^ a[3] ^ + a[2] ^ b[3]; + new_index[4] = a[18] ^ a[16] ^ a[15] ^ a[14] ^ a[13] ^ a[10] ^ a[8] ^ a[4] ^ + a[3] ^ b[4]; + new_index[5] = + a[17] ^ a[16] ^ a[15] ^ a[14] ^ a[11] ^ a[9] ^ a[5] ^ a[4] ^ b[5]; + return new_index.to_ulong(); + } else { /* Else incorrect number of channels for the hashing function */ + assert( + "\nmemory_partition_indexing error: The number of " + "channels should be " + "16, 32 or 64 for the hashing IPOLY index function. other banks " + "numbers are not supported. Generate it by yourself! \n" && + 0); + + return 0; + } +} + +unsigned bitwise_hash_function(new_addr_type higher_bits, unsigned index, + unsigned bank_set_num) { + return (index) ^ (higher_bits & (bank_set_num - 1)); +} + +unsigned PAE_hash_function(new_addr_type higher_bits, unsigned index, + unsigned bank_set_num) { + // Page Address Entropy + // random selected bits from the page and bank bits + // similar to + // Liu, Yuxi, et al. "Get Out of the Valley: Power-Efficient Address + if (bank_set_num == 32) { + std::bitset<64> a(higher_bits); + std::bitset<5> b(index); + std::bitset<5> new_index(index); + new_index[0] = a[13] ^ a[10] ^ a[9] ^ a[5] ^ a[0] ^ b[3] ^ b[0] ^ b[0]; + new_index[1] = a[12] ^ a[11] ^ a[6] ^ a[1] ^ b[3] ^ b[2] ^ b[1] ^ b[1]; + new_index[2] = a[14] ^ a[9] ^ a[8] ^ a[7] ^ a[2] ^ b[1] ^ b[2]; + new_index[3] = a[11] ^ a[10] ^ a[8] ^ a[3] ^ b[2] ^ b[3] ^ b[3]; + new_index[4] = a[12] ^ a[9] ^ a[8] ^ a[5] ^ a[4] ^ b[1] ^ b[0] ^ b[4]; + + return new_index.to_ulong(); + } else { + assert(0); + return 0; + } +} diff --git a/src/gpgpu-sim/hashing.h b/src/gpgpu-sim/hashing.h new file mode 100644 index 0000000..867c949 --- /dev/null +++ b/src/gpgpu-sim/hashing.h @@ -0,0 +1,24 @@ +// author: Mahmoud Khairy, (Purdue Univ) +// email: [email protected] + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include "../option_parser.h" + +#ifndef HASHING_H +#define HASHING_H + +#include "../abstract_hardware_model.h" +#include "gpu-cache.h" + +unsigned ipoly_hash_function(new_addr_type higher_bits, unsigned index, + unsigned bank_set_num); + +unsigned bitwise_hash_function(new_addr_type higher_bits, unsigned index, + unsigned bank_set_num); + +unsigned PAE_hash_function(new_addr_type higher_bits, unsigned index, + unsigned bank_set_num); + +#endif diff --git a/src/gpgpu-sim/icnt_wrapper.cc b/src/gpgpu-sim/icnt_wrapper.cc index 890638a..82785dc 100644 --- a/src/gpgpu-sim/icnt_wrapper.cc +++ b/src/gpgpu-sim/icnt_wrapper.cc @@ -144,16 +144,20 @@ void icnt_reg_options(class OptionParser* opp) { "Interconnection network config file", "mesh"); // parameters for local xbar - option_parser_register(opp, "-inct_in_buffer_limit", OPT_UINT32, + option_parser_register(opp, "-icnt_in_buffer_limit", OPT_UINT32, &g_inct_config.in_buffer_limit, "in_buffer_limit", "64"); - option_parser_register(opp, "-inct_out_buffer_limit", OPT_UINT32, + option_parser_register(opp, "-icnt_out_buffer_limit", OPT_UINT32, &g_inct_config.out_buffer_limit, "out_buffer_limit", "64"); - option_parser_register(opp, "-inct_subnets", OPT_UINT32, + option_parser_register(opp, "-icnt_subnets", OPT_UINT32, &g_inct_config.subnets, "subnets", "2"); - option_parser_register(opp, "-arbiter_algo", OPT_UINT32, + option_parser_register(opp, "-icnt_arbiter_algo", OPT_UINT32, &g_inct_config.arbiter_algo, "arbiter_algo", "1"); + option_parser_register(opp, "-icnt_verbose", OPT_UINT32, + &g_inct_config.verbose, "inct_verbose", "0"); + option_parser_register(opp, "-icnt_grant_cycles", OPT_UINT32, + &g_inct_config.grant_cycles, "grant_cycles", "1"); } void icnt_wrapper_init() { diff --git a/src/gpgpu-sim/local_interconnect.cc b/src/gpgpu-sim/local_interconnect.cc index cd32386..0e20462 100644 --- a/src/gpgpu-sim/local_interconnect.cc +++ b/src/gpgpu-sim/local_interconnect.cc @@ -39,20 +39,21 @@ xbar_router::xbar_router(unsigned router_id, enum Interconnect_type m_type, unsigned n_shader, unsigned n_mem, - unsigned m_in_buffer_limit, - unsigned m_out_buffer_limit, - enum Arbiteration_type m_arbit_type) { + const struct inct_config& m_localinct_config) { m_id = router_id; router_type = m_type; _n_mem = n_mem; _n_shader = n_shader; total_nodes = n_shader + n_mem; + verbose = m_localinct_config.verbose; + grant_cycles = m_localinct_config.grant_cycles; + grant_cycles_count = m_localinct_config.grant_cycles; in_buffers.resize(total_nodes); out_buffers.resize(total_nodes); next_node.resize(total_nodes, 0); - in_buffer_limit = m_in_buffer_limit; - out_buffer_limit = m_out_buffer_limit; - arbit_type = m_arbit_type; + in_buffer_limit = m_localinct_config.in_buffer_limit; + out_buffer_limit = m_localinct_config.out_buffer_limit; + arbit_type = m_localinct_config.arbiter_algo; next_node_id = 0; if (m_type == REQ_NET) { active_in_buffers = n_shader; @@ -69,6 +70,9 @@ xbar_router::xbar_router(unsigned router_id, enum Interconnect_type m_type, out_buffer_util = 0; in_buffer_util = 0; packets_num = 0; + conflicts_util = 0; + cycles_util = 0; + reqs_util = 0; } xbar_router::~xbar_router() {} @@ -117,14 +121,16 @@ void xbar_router::Advance() { } void xbar_router::RR_Advance() { - cycles++; - + bool active = false; vector<bool> issued(total_nodes, false); + unsigned conflict_sub = 0; + unsigned reqs = 0; for (unsigned i = 0; i < total_nodes; ++i) { unsigned node_id = (i + next_node_id) % total_nodes; if (!in_buffers[node_id].empty()) { + active = true; Packet _packet = in_buffers[node_id].front(); // ensure that the outbuffer has space and not issued before in this cycle if (Has_Buffer_Out(_packet.output_deviceID, 1)) { @@ -132,23 +138,38 @@ void xbar_router::RR_Advance() { out_buffers[_packet.output_deviceID].push(_packet); in_buffers[node_id].pop(); issued[_packet.output_deviceID] = true; + reqs++; } else - conflicts++; + conflict_sub++; } else { out_buffer_full++; - if (issued[_packet.output_deviceID]) conflicts++; + if (issued[_packet.output_deviceID]) conflict_sub++; } } } next_node_id = (++next_node_id % total_nodes); + conflicts += conflict_sub; + if (active) { + conflicts_util += conflict_sub; + cycles_util++; + reqs_util += reqs; + } + + if (verbose) { + printf("%d : cycle %d : conflicts = %d\n", m_id, cycles, conflict_sub); + printf("%d : cycle %d : passing reqs = %d\n", m_id, cycles, reqs); + } + // collect some stats about buffer util for (unsigned i = 0; i < total_nodes; ++i) { in_buffer_util += in_buffers[i].size(); out_buffer_util += out_buffers[i].size(); } + + cycles++; } // iSLIP algorithm @@ -156,9 +177,11 @@ void xbar_router::RR_Advance() { // IEEE/ACM transactions on networking 2 (1999): 188-201. // https://www.cs.rutgers.edu/~sn624/552-F18/papers/islip.pdf void xbar_router::iSLIP_Advance() { - cycles++; - vector<unsigned> node_tmp; + bool active = false; + + unsigned conflict_sub = 0; + unsigned reqs = 0; // calcaulte how many conflicts are there for stats for (unsigned i = 0; i < total_nodes; ++i) { @@ -167,15 +190,21 @@ void xbar_router::iSLIP_Advance() { if (!node_tmp.empty()) { if (std::find(node_tmp.begin(), node_tmp.end(), _packet_tmp.output_deviceID) != node_tmp.end()) { - conflicts++; + conflict_sub++; } else node_tmp.push_back(_packet_tmp.output_deviceID); } else { node_tmp.push_back(_packet_tmp.output_deviceID); } + active = true; } } + conflicts += conflict_sub; + if (active) { + conflicts_util += conflict_sub; + cycles_util++; + } // do iSLIP for (unsigned i = 0; i < total_nodes; ++i) { if (Has_Buffer_Out(i, 1)) { @@ -187,7 +216,25 @@ void xbar_router::iSLIP_Advance() { if (_packet.output_deviceID == i) { out_buffers[_packet.output_deviceID].push(_packet); in_buffers[node_id].pop(); - next_node[i] = (++node_id % total_nodes); + if (verbose) + printf("%d : cycle %d : send req from %d to %d\n", m_id, cycles, + node_id, i - _n_shader); + if (grant_cycles_count == 1) + next_node[i] = (++node_id % total_nodes); + if (verbose) { + for (unsigned k = j + 1; k < total_nodes; ++k) { + unsigned node_id2 = (k + next_node[i]) % total_nodes; + if (!in_buffers[node_id2].empty()) { + Packet _packet2 = in_buffers[node_id2].front(); + + if (_packet2.output_deviceID == i) + printf("%d : cycle %d : cannot send req from %d to %d\n", + m_id, cycles, node_id2, i - _n_shader); + } + } + } + + reqs++; break; } } @@ -196,11 +243,30 @@ void xbar_router::iSLIP_Advance() { out_buffer_full++; } + if (active) { + reqs_util += reqs; + } + + if (verbose) + printf("%d : cycle %d : grant_cycles = %d\n", m_id, cycles, grant_cycles); + + if (active && grant_cycles_count == 1) + grant_cycles_count = grant_cycles; + else if (active) + grant_cycles_count--; + + if (verbose) { + printf("%d : cycle %d : conflicts = %d\n", m_id, cycles, conflict_sub); + printf("%d : cycle %d : passing reqs = %d\n", m_id, cycles, reqs); + } + // collect some stats about buffer util for (unsigned i = 0; i < total_nodes; ++i) { in_buffer_util += in_buffers[i].size(); out_buffer_util += out_buffers[i].size(); } + + cycles++; } bool xbar_router::Busy() const { @@ -247,9 +313,7 @@ void LocalInterconnect::CreateInterconnect(unsigned m_n_shader, net.resize(n_subnets); for (unsigned i = 0; i < n_subnets; ++i) { net[i] = new xbar_router(i, static_cast<Interconnect_type>(i), m_n_shader, - m_n_mem, m_inct_config.in_buffer_limit, - m_inct_config.out_buffer_limit, - m_inct_config.arbiter_algo); + m_n_mem, m_inct_config); } } @@ -312,51 +376,51 @@ bool LocalInterconnect::HasBuffer(unsigned deviceID, unsigned int size) const { } void LocalInterconnect::DisplayStats() const { - cout << "Req_Network_injected_packets_num = " << net[REQ_NET]->packets_num - << endl; - cout << "Req_Network_cycles = " << net[REQ_NET]->cycles << endl; - cout << "Req_Network_injected_packets_per_cycle = " - << (float)(net[REQ_NET]->packets_num) / (net[REQ_NET]->cycles) << endl; - cout << "Req_Network_conflicts_per_cycle = " - << (float)(net[REQ_NET]->conflicts) / (net[REQ_NET]->cycles) << endl; - cout << "Req_Network_in_buffer_full_per_cycle = " - << (float)(net[REQ_NET]->in_buffer_full) / (net[REQ_NET]->cycles) - << endl; - cout << "Req_Network_in_buffer_avg_util = " - << ((float)(net[REQ_NET]->in_buffer_util) / (net[REQ_NET]->cycles) / - net[REQ_NET]->active_in_buffers) - << endl; - cout << "Req_Network_out_buffer_full_per_cycle = " - << (float)(net[REQ_NET]->out_buffer_full) / (net[REQ_NET]->cycles) - << endl; - cout << "Req_Network_out_buffer_avg_util = " - << ((float)(net[REQ_NET]->out_buffer_util) / (net[REQ_NET]->cycles) / - net[REQ_NET]->active_out_buffers) - << endl; + printf("Req_Network_injected_packets_num = %lld\n", + net[REQ_NET]->packets_num); + printf("Req_Network_cycles = %lld\n", net[REQ_NET]->cycles); + printf("Req_Network_injected_packets_per_cycle = %12.4f \n", + (float)(net[REQ_NET]->packets_num) / (net[REQ_NET]->cycles)); + printf("Req_Network_conflicts_per_cycle = %12.4f\n", + (float)(net[REQ_NET]->conflicts) / (net[REQ_NET]->cycles)); + printf("Req_Network_conflicts_per_cycle_util = %12.4f\n", + (float)(net[REQ_NET]->conflicts_util) / (net[REQ_NET]->cycles_util)); + printf("Req_Bank_Level_Parallism = %12.4f\n", + (float)(net[REQ_NET]->reqs_util) / (net[REQ_NET]->cycles_util)); + printf("Req_Network_in_buffer_full_per_cycle = %12.4f\n", + (float)(net[REQ_NET]->in_buffer_full) / (net[REQ_NET]->cycles)); + printf("Req_Network_in_buffer_avg_util = %12.4f\n", + ((float)(net[REQ_NET]->in_buffer_util) / (net[REQ_NET]->cycles) / + net[REQ_NET]->active_in_buffers)); + printf("Req_Network_out_buffer_full_per_cycle = %12.4f\n", + (float)(net[REQ_NET]->out_buffer_full) / (net[REQ_NET]->cycles)); + printf("Req_Network_out_buffer_avg_util = %12.4f\n", + ((float)(net[REQ_NET]->out_buffer_util) / (net[REQ_NET]->cycles) / + net[REQ_NET]->active_out_buffers)); - cout << endl; - cout << "Reply_Network_injected_packets_num = " << net[REPLY_NET]->packets_num - << endl; - cout << "Reply_Network_cycles = " << net[REPLY_NET]->cycles << endl; - cout << "Reply_Network_injected_packets_per_cycle = " - << (float)(net[REPLY_NET]->packets_num) / (net[REPLY_NET]->cycles) - << endl; - cout << "Reply_Network_conflicts_per_cycle = " - << (float)(net[REPLY_NET]->conflicts) / (net[REPLY_NET]->cycles) << endl; - cout << "Reply_Network_in_buffer_full_per_cycle = " - << (float)(net[REPLY_NET]->in_buffer_full) / (net[REPLY_NET]->cycles) - << endl; - cout << "Reply_Network_in_buffer_avg_util = " - << ((float)(net[REPLY_NET]->in_buffer_util) / (net[REPLY_NET]->cycles) / - net[REPLY_NET]->active_in_buffers) - << endl; - cout << "Reply_Network_out_buffer_full_per_cycle = " - << (float)(net[REPLY_NET]->out_buffer_full) / (net[REPLY_NET]->cycles) - << endl; - cout << "Reply_Network_out_buffer_avg_util= " - << ((float)(net[REPLY_NET]->out_buffer_util) / (net[REPLY_NET]->cycles) / - net[REPLY_NET]->active_out_buffers) - << endl; + printf("\n"); + printf("Reply_Network_injected_packets_num = %lld\n", + net[REPLY_NET]->packets_num); + printf("Reply_Network_cycles = %lld\n", net[REPLY_NET]->cycles); + printf("Reply_Network_injected_packets_per_cycle = %12.4f\n", + (float)(net[REPLY_NET]->packets_num) / (net[REPLY_NET]->cycles)); + printf("Reply_Network_conflicts_per_cycle = %12.4f\n", + (float)(net[REPLY_NET]->conflicts) / (net[REPLY_NET]->cycles)); + printf( + "Reply_Network_conflicts_per_cycle_util = %12.4f\n", + (float)(net[REPLY_NET]->conflicts_util) / (net[REPLY_NET]->cycles_util)); + printf("Reply_Bank_Level_Parallism = %12.4f\n", + (float)(net[REPLY_NET]->reqs_util) / (net[REPLY_NET]->cycles_util)); + printf("Reply_Network_in_buffer_full_per_cycle = %12.4f\n", + (float)(net[REPLY_NET]->in_buffer_full) / (net[REPLY_NET]->cycles)); + printf("Reply_Network_in_buffer_avg_util = %12.4f\n", + ((float)(net[REPLY_NET]->in_buffer_util) / (net[REPLY_NET]->cycles) / + net[REPLY_NET]->active_in_buffers)); + printf("Reply_Network_out_buffer_full_per_cycle = %12.4f\n", + (float)(net[REPLY_NET]->out_buffer_full) / (net[REPLY_NET]->cycles)); + printf("Reply_Network_out_buffer_avg_util = %12.4f\n", + ((float)(net[REPLY_NET]->out_buffer_util) / (net[REPLY_NET]->cycles) / + net[REPLY_NET]->active_out_buffers)); } void LocalInterconnect::DisplayOverallStats() const {} diff --git a/src/gpgpu-sim/local_interconnect.h b/src/gpgpu-sim/local_interconnect.h index 29cd903..dd10a06 100644 --- a/src/gpgpu-sim/local_interconnect.h +++ b/src/gpgpu-sim/local_interconnect.h @@ -45,13 +45,15 @@ struct inct_config { unsigned out_buffer_limit; unsigned subnets; Arbiteration_type arbiter_algo; + unsigned verbose; + unsigned grant_cycles; }; class xbar_router { public: xbar_router(unsigned router_id, enum Interconnect_type m_type, - unsigned n_shader, unsigned n_mem, unsigned m_in_buffer_limit, - unsigned m_out_buffer_limit, enum Arbiteration_type m_arbit_type); + unsigned n_shader, unsigned n_mem, + const struct inct_config& m_localinct_config); ~xbar_router(); void Push(unsigned input_deviceID, unsigned output_deviceID, void* data, unsigned int size); @@ -66,6 +68,9 @@ class xbar_router { // some stats unsigned long long cycles; unsigned long long conflicts; + unsigned long long conflicts_util; + unsigned long long cycles_util; + unsigned long long reqs_util; unsigned long long out_buffer_full; unsigned long long out_buffer_util; unsigned long long in_buffer_full; @@ -94,6 +99,10 @@ class xbar_router { enum Interconnect_type router_type; unsigned active_in_buffers, active_out_buffers; Arbiteration_type arbit_type; + unsigned verbose; + + unsigned grant_cycles; + unsigned grant_cycles_count; friend class LocalInterconnect; }; diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc index 7cb02cf..456d891 100644 --- a/src/gpgpu-sim/mem_fetch.cc +++ b/src/gpgpu-sim/mem_fetch.cc @@ -65,6 +65,10 @@ mem_fetch::mem_fetch(const mem_access_t &access, const warp_inst_t *inst, icnt_flit_size = config->icnt_flit_size; original_mf = m_original_mf; original_wr_mf = m_original_wr_mf; + if (m_original_mf) { + m_raw_addr.chip = m_original_mf->get_tlx_addr().chip; + m_raw_addr.sub_partition = m_original_mf->get_tlx_addr().sub_partition; + } } mem_fetch::~mem_fetch() { m_status = MEM_FETCH_DELETED; } diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h index 71d8acd..e039846 100644 --- a/src/gpgpu-sim/mem_fetch.h +++ b/src/gpgpu-sim/mem_fetch.h @@ -76,6 +76,10 @@ class mem_fetch { void print(FILE *fp, bool print_inst = true) const; const addrdec_t &get_tlx_addr() const { return m_raw_addr; } + void set_chip(unsigned chip_id) { m_raw_addr.chip = chip_id; } + void set_parition(unsigned sub_partition_id) { + m_raw_addr.sub_partition = sub_partition_id; + } unsigned get_data_size() const { return m_data_size; } void set_data_size(unsigned size) { m_data_size = size; } unsigned get_ctrl_size() const { return m_ctrl_size; } diff --git a/src/gpgpu-sim/mem_latency_stat.cc b/src/gpgpu-sim/mem_latency_stat.cc index e50ad9e..63d7ee8 100644 --- a/src/gpgpu-sim/mem_latency_stat.cc +++ b/src/gpgpu-sim/mem_latency_stat.cc @@ -39,9 +39,11 @@ #include "stat-tool.h" #include "visualizer.h" +#include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> + #include "../../libcuda/gpgpu_context.h" memory_stats_t::memory_stats_t(unsigned n_shader, @@ -226,14 +228,18 @@ void memory_stats_t::memlatstat_dram_access(mem_fetch *mf) { bankwrites[mf->get_sid()][dram_id][bank]++; shader_mem_acc_log(mf->get_sid(), dram_id, bank, 'w'); } - totalbankwrites[dram_id][bank]++; + totalbankwrites[dram_id][bank] += + ceil(mf->get_data_size() / m_memory_config->dram_atom_size); } else { bankreads[mf->get_sid()][dram_id][bank]++; shader_mem_acc_log(mf->get_sid(), dram_id, bank, 'r'); - totalbankreads[dram_id][bank]++; + totalbankreads[dram_id][bank] += + ceil(mf->get_data_size() / m_memory_config->dram_atom_size); } - mem_access_type_stats[mf->get_access_type()][dram_id][bank]++; + mem_access_type_stats[mf->get_access_type()][dram_id][bank] += + ceil(mf->get_data_size() / m_memory_config->dram_atom_size); } + if (mf->get_pc() != (unsigned)-1) m_gpu->gpgpu_ctx->stats->ptx_file_line_stats_add_dram_traffic( mf->get_pc(), mf->get_data_size()); diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index b596c0d..c6e7b8f 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -74,32 +74,38 @@ std::list<unsigned> shader_core_ctx::get_regs_written(const inst_t &fvt) const { return result; } -shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, - class simt_core_cluster *cluster, - unsigned shader_id, unsigned tpc_id, - const shader_core_config *config, - const memory_config *mem_config, - shader_core_stats *stats) - : core_t(gpu, NULL, config->warp_size, config->n_thread_per_shader), - m_barriers(this, config->max_warps_per_shader, config->max_cta_per_core, - config->max_barriers_per_cta, config->warp_size), - m_active_warps(0), - m_dynamic_warp_id(0) { - m_cluster = cluster; - m_config = config; - m_memory_config = mem_config; - m_stats = stats; - unsigned warp_size = config->warp_size; - Issue_Prio = 0; - - m_sid = shader_id; - m_tpc = tpc_id; +void exec_shader_core_ctx::create_shd_warp() { + m_warp.resize(m_config->max_warps_per_shader); + for (unsigned k = 0; k < m_config->max_warps_per_shader; ++k) { + m_warp[k] = new shd_warp_t(this, m_config->warp_size); + } +} - m_pipeline_reg.reserve(N_PIPELINE_STAGES); +void shader_core_ctx::create_front_pipeline() { + // pipeline_stages is the sum of normal pipeline stages and specialized_unit + // stages * 2 (for ID and EX) + unsigned total_pipeline_stages = + N_PIPELINE_STAGES + m_config->m_specialized_unit.size() * 2; + m_pipeline_reg.reserve(total_pipeline_stages); for (int j = 0; j < N_PIPELINE_STAGES; j++) { m_pipeline_reg.push_back( register_set(m_config->pipe_widths[j], pipeline_stage_name_decode[j])); } + for (int j = 0; j < m_config->m_specialized_unit.size(); j++) { + m_pipeline_reg.push_back( + register_set(m_config->m_specialized_unit[j].id_oc_spec_reg_width, + m_config->m_specialized_unit[j].name)); + m_config->m_specialized_unit[j].ID_OC_SPEC_ID = m_pipeline_reg.size() - 1; + m_specilized_dispatch_reg.push_back( + &m_pipeline_reg[m_pipeline_reg.size() - 1]); + } + for (int j = 0; j < m_config->m_specialized_unit.size(); j++) { + m_pipeline_reg.push_back( + register_set(m_config->m_specialized_unit[j].oc_ex_spec_reg_width, + m_config->m_specialized_unit[j].name)); + m_config->m_specialized_unit[j].OC_EX_SPEC_ID = m_pipeline_reg.size() - 1; + } + if (m_config->sub_core_model) { // in subcore model, each scheduler should has its own issue register, so // num scheduler = reg width @@ -120,14 +126,14 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, m_pipeline_reg[ID_OC_INT].get_size()); } - m_threadState = - (thread_ctx_t *)calloc(sizeof(thread_ctx_t), config->n_thread_per_shader); + m_threadState = (thread_ctx_t *)calloc(sizeof(thread_ctx_t), + m_config->n_thread_per_shader); m_not_completed = 0; m_active_threads.reset(); m_n_active_cta = 0; for (unsigned i = 0; i < MAX_CTA_PER_SHADER; i++) m_cta_status[i] = 0; - for (unsigned i = 0; i < config->n_thread_per_shader; i++) { + for (unsigned i = 0; i < m_config->n_thread_per_shader; i++) { m_thread[i] = NULL; m_threadState[i].m_cta_id = -1; m_threadState[i].m_active = false; @@ -135,12 +141,12 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, // m_icnt = new shader_memory_interface(this,cluster); if (m_config->gpgpu_perfect_mem) { - m_icnt = new perfect_memory_interface(this, cluster); + m_icnt = new perfect_memory_interface(this, m_cluster); } else { - m_icnt = new shader_memory_interface(this, cluster); + m_icnt = new shader_memory_interface(this, m_cluster); } m_mem_fetch_allocator = - new shader_core_mem_fetch_allocator(shader_id, tpc_id, mem_config); + new shader_core_mem_fetch_allocator(m_sid, m_tpc, m_memory_config); // fetch m_last_warp_fetched = 0; @@ -151,9 +157,10 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, m_L1I = new read_only_cache(name, m_config->m_L1I_config, m_sid, get_shader_instruction_cache_id(), m_icnt, IN_L1I_MISS_QUEUE); +} - m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size)); - m_scoreboard = new Scoreboard(m_sid, m_config->max_warps_per_shader, gpu); +void shader_core_ctx::create_schedulers() { + m_scoreboard = new Scoreboard(m_sid, m_config->max_warps_per_shader, m_gpu); // scedulers // must currently occur after all inputs have been initialized. @@ -180,37 +187,40 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, m_stats, this, m_scoreboard, m_simt_stack, &m_warp, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], &m_pipeline_reg[ID_OC_INT], - &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i)); + &m_pipeline_reg[ID_OC_TENSOR_CORE], m_specilized_dispatch_reg, + &m_pipeline_reg[ID_OC_MEM], i)); break; case CONCRETE_SCHEDULER_TWO_LEVEL_ACTIVE: schedulers.push_back(new two_level_active_scheduler( m_stats, this, m_scoreboard, m_simt_stack, &m_warp, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], &m_pipeline_reg[ID_OC_INT], - &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i, - config->gpgpu_scheduler_string)); + &m_pipeline_reg[ID_OC_TENSOR_CORE], m_specilized_dispatch_reg, + &m_pipeline_reg[ID_OC_MEM], i, m_config->gpgpu_scheduler_string)); break; case CONCRETE_SCHEDULER_GTO: schedulers.push_back(new gto_scheduler( m_stats, this, m_scoreboard, m_simt_stack, &m_warp, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], &m_pipeline_reg[ID_OC_INT], - &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i)); + &m_pipeline_reg[ID_OC_TENSOR_CORE], m_specilized_dispatch_reg, + &m_pipeline_reg[ID_OC_MEM], i)); break; case CONCRETE_SCHEDULER_OLDEST_FIRST: schedulers.push_back(new oldest_scheduler( m_stats, this, m_scoreboard, m_simt_stack, &m_warp, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], &m_pipeline_reg[ID_OC_INT], - &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i)); + &m_pipeline_reg[ID_OC_TENSOR_CORE], m_specilized_dispatch_reg, + &m_pipeline_reg[ID_OC_MEM], i)); break; case CONCRETE_SCHEDULER_WARP_LIMITING: schedulers.push_back(new swl_scheduler( m_stats, this, m_scoreboard, m_simt_stack, &m_warp, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], &m_pipeline_reg[ID_OC_INT], - &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i, - config->gpgpu_scheduler_string)); + &m_pipeline_reg[ID_OC_TENSOR_CORE], m_specilized_dispatch_reg, + &m_pipeline_reg[ID_OC_MEM], i, m_config->gpgpu_scheduler_string)); break; default: abort(); @@ -225,9 +235,10 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, for (unsigned i = 0; i < m_config->gpgpu_num_sched_per_core; ++i) { schedulers[i]->done_adding_supervised_warps(); } +} +void shader_core_ctx::create_exec_pipeline() { // op collector configuration - enum { SP_CUS, DP_CUS, SFU_CUS, TENSOR_CORE_CUS, INT_CUS, MEM_CUS, GEN_CUS }; opndcoll_rfu_t::port_vector_t in_ports; @@ -259,6 +270,14 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, in_ports.push_back(&m_pipeline_reg[ID_OC_INT]); out_ports.push_back(&m_pipeline_reg[OC_EX_INT]); } + if (m_config->m_specialized_unit.size() > 0) { + for (unsigned j = 0; j < m_config->m_specialized_unit.size(); ++j) { + in_ports.push_back( + &m_pipeline_reg[m_config->m_specialized_unit[j].ID_OC_SPEC_ID]); + out_ports.push_back( + &m_pipeline_reg[m_config->m_specialized_unit[j].OC_EX_SPEC_ID]); + } + } cu_sets.push_back((unsigned)GEN_CUS); m_operand_collector.add_port(in_ports, out_ports, cu_sets); in_ports.clear(), out_ports.clear(), cu_sets.clear(); @@ -272,8 +291,9 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, DP_CUS, m_config->gpgpu_operand_collector_num_units_dp, m_config->gpgpu_operand_collector_num_out_ports_dp); m_operand_collector.add_cu_set( - TENSOR_CORE_CUS, config->gpgpu_operand_collector_num_units_tensor_core, - config->gpgpu_operand_collector_num_out_ports_tensor_core); + TENSOR_CORE_CUS, + m_config->gpgpu_operand_collector_num_units_tensor_core, + m_config->gpgpu_operand_collector_num_out_ports_tensor_core); m_operand_collector.add_cu_set( SFU_CUS, m_config->gpgpu_operand_collector_num_units_sfu, m_config->gpgpu_operand_collector_num_out_ports_sfu); @@ -315,7 +335,7 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, } for (unsigned i = 0; - i < config->gpgpu_operand_collector_num_in_ports_tensor_core; i++) { + i < m_config->gpgpu_operand_collector_num_in_ports_tensor_core; i++) { in_ports.push_back(&m_pipeline_reg[ID_OC_TENSOR_CORE]); out_ports.push_back(&m_pipeline_reg[OC_EX_TENSOR_CORE]); cu_sets.push_back((unsigned)TENSOR_CORE_CUS); @@ -350,7 +370,7 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, m_num_function_units = m_config->gpgpu_num_sp_units + m_config->gpgpu_num_dp_units + m_config->gpgpu_num_sfu_units + m_config->gpgpu_num_tensor_core_units + - m_config->gpgpu_num_int_units + + m_config->gpgpu_num_int_units + m_config->m_specialized_unit_num + 1; // sp_unit, sfu, dp, tensor, int, ldst_unit // m_dispatch_port = new enum pipeline_stage_name_t[ m_num_function_units ]; // m_issue_port = new enum pipeline_stage_name_t[ m_num_function_units ]; @@ -380,15 +400,26 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, m_issue_port.push_back(OC_EX_SFU); } - for (int k = 0; k < config->gpgpu_num_tensor_core_units; k++) { + for (int k = 0; k < m_config->gpgpu_num_tensor_core_units; k++) { m_fu.push_back(new tensor_core(&m_pipeline_reg[EX_WB], m_config, this)); m_dispatch_port.push_back(ID_OC_TENSOR_CORE); m_issue_port.push_back(OC_EX_TENSOR_CORE); } - m_ldst_unit = - new ldst_unit(m_icnt, m_mem_fetch_allocator, this, &m_operand_collector, - m_scoreboard, config, mem_config, stats, shader_id, tpc_id); + for (int j = 0; j < m_config->m_specialized_unit.size(); j++) { + for (unsigned k = 0; k < m_config->m_specialized_unit[j].num_units; k++) { + m_fu.push_back(new specialized_unit( + &m_pipeline_reg[EX_WB], m_config, this, SPEC_UNIT_START_ID + j, + m_config->m_specialized_unit[j].name, + m_config->m_specialized_unit[j].latency)); + m_dispatch_port.push_back(m_config->m_specialized_unit[j].ID_OC_SPEC_ID); + m_issue_port.push_back(m_config->m_specialized_unit[j].OC_EX_SPEC_ID); + } + } + + m_ldst_unit = new ldst_unit(m_icnt, m_mem_fetch_allocator, this, + &m_operand_collector, m_scoreboard, m_config, + m_memory_config, m_stats, m_sid, m_tpc); m_fu.push_back(m_ldst_unit); m_dispatch_port.push_back(ID_OC_MEM); m_issue_port.push_back(OC_EX_MEM); @@ -398,10 +429,32 @@ shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, m_fu.size() == m_issue_port.size()); // there are as many result buses as the width of the EX_WB stage - num_result_bus = config->pipe_widths[EX_WB]; + num_result_bus = m_config->pipe_widths[EX_WB]; for (unsigned i = 0; i < num_result_bus; i++) { this->m_result_bus.push_back(new std::bitset<MAX_ALU_LATENCY>()); } +} + +shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, + class simt_core_cluster *cluster, + unsigned shader_id, unsigned tpc_id, + const shader_core_config *config, + const memory_config *mem_config, + shader_core_stats *stats) + : core_t(gpu, NULL, config->warp_size, config->n_thread_per_shader), + m_barriers(this, config->max_warps_per_shader, config->max_cta_per_core, + config->max_barriers_per_cta, config->warp_size), + m_active_warps(0), + m_dynamic_warp_id(0) { + m_cluster = cluster; + m_config = config; + m_memory_config = mem_config; + m_stats = stats; + unsigned warp_size = config->warp_size; + Issue_Prio = 0; + + m_sid = shader_id; + m_tpc = tpc_id; m_last_inst_gpu_sim_cycle = 0; m_last_inst_gpu_tot_sim_cycle = 0; @@ -436,15 +489,17 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, } for (unsigned i = start_thread / m_config->warp_size; i < end_thread / m_config->warp_size; ++i) { - m_warp[i].reset(); + m_warp[i]->reset(); m_simt_stack[i]->reset(); } } void shader_core_ctx::init_warps(unsigned cta_id, unsigned start_thread, unsigned end_thread, unsigned ctaid, - int cta_size, unsigned kernel_id) { + int cta_size, kernel_info_t &kernel) { + // address_type start_pc = next_pc(start_thread); + unsigned kernel_id = kernel.get_uid(); if (m_config->model == POST_DOMINATOR) { unsigned start_warp = start_thread / m_config->warp_size; unsigned warp_per_cta = cta_size / m_config->warp_size; @@ -473,13 +528,15 @@ void shader_core_ctx::init_warps(unsigned cta_id, unsigned start_thread, m_simt_stack[i]->resume(fname); m_simt_stack[i]->get_pdom_stack_top_info(&pc, &rpc); for (unsigned t = 0; t < m_config->warp_size; t++) { - m_thread[i * m_config->warp_size + t]->set_npc(pc); - m_thread[i * m_config->warp_size + t]->update_pc(); + if (m_thread != NULL) { + m_thread[i * m_config->warp_size + t]->set_npc(pc); + m_thread[i * m_config->warp_size + t]->update_pc(); + } } start_pc = pc; } - m_warp[i].init(start_pc, cta_id, i, active_threads, m_dynamic_warp_id); + m_warp[i]->init(start_pc, cta_id, i, active_threads, m_dynamic_warp_id); ++m_dynamic_warp_id; m_not_completed += n_active; ++m_active_warps; @@ -691,6 +748,8 @@ void shader_core_stats::visualizer_print(gzFile visualizer_file) { } gzprintf(visualizer_file, "\n"); + gzprintf(visualizer_file, "ctas_completed: %d\n", ctas_completed); + ctas_completed = 0; // warp issue breakdown unsigned sid = m_config->gpgpu_warp_issue_shader; unsigned count = 0; @@ -772,13 +831,32 @@ void shader_core_stats::visualizer_print(gzFile visualizer_file) { 0xF0000000 /* should be distinct from other memory spaces... \ check ptx_ir.h to verify this does not overlap \ other memory spaces */ + +const warp_inst_t *exec_shader_core_ctx::get_next_inst(unsigned warp_id, + address_type pc) { + // read the inst from the functional model + return m_gpu->gpgpu_ctx->ptx_fetch_inst(pc); +} + +void exec_shader_core_ctx::get_pdom_stack_top_info(unsigned warp_id, + const warp_inst_t *pI, + unsigned *pc, + unsigned *rpc) { + m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc); +} + +const active_mask_t &exec_shader_core_ctx::get_active_mask( + unsigned warp_id, const warp_inst_t *pI) { + return m_simt_stack[warp_id]->get_active_mask(); +} + void shader_core_ctx::decode() { 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 warp_inst_t *pI1 = m_gpu->gpgpu_ctx->ptx_fetch_inst(pc); - 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 warp_inst_t *pI1 = get_next_inst(m_inst_fetch_buffer.m_warp_id, pc); + 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(); if (pI1) { m_stats->m_num_decoded_insn[m_sid]++; if (pI1->oprnd_type == INT_OP) { @@ -787,10 +865,10 @@ void shader_core_ctx::decode() { m_stats->m_num_FPdecoded_insn[m_sid]++; } const warp_inst_t *pI2 = - m_gpu->gpgpu_ctx->ptx_fetch_inst(pc + pI1->isize); + get_next_inst(m_inst_fetch_buffer.m_warp_id, 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_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_stats->m_num_decoded_insn[m_sid]++; if (pI2->oprnd_type == INT_OP) { m_stats->m_num_INTdecoded_insn[m_sid]++; @@ -807,15 +885,16 @@ void shader_core_ctx::fetch() { if (!m_inst_fetch_buffer.m_valid) { if (m_L1I->access_ready()) { mem_fetch *mf = m_L1I->next_access(); - m_warp[mf->get_wid()].clear_imiss_pending(); - m_inst_fetch_buffer = ifetch_buffer_t( - m_warp[mf->get_wid()].get_pc(), mf->get_access_size(), mf->get_wid()); - assert(m_warp[mf->get_wid()].get_pc() == + m_warp[mf->get_wid()]->clear_imiss_pending(); + m_inst_fetch_buffer = + ifetch_buffer_t(m_warp[mf->get_wid()]->get_pc(), + mf->get_access_size(), mf->get_wid()); + assert(m_warp[mf->get_wid()]->get_pc() == (mf->get_addr() - PROGRAM_MEM_START)); // Verify that we got the instruction we // were expecting. m_inst_fetch_buffer.m_valid = true; - m_warp[mf->get_wid()].set_last_fetch(m_gpu->gpu_sim_cycle); + m_warp[mf->get_wid()]->set_last_fetch(m_gpu->gpu_sim_cycle); delete mf; } else { // find an active warp with space in instruction buffer that is not @@ -827,33 +906,37 @@ void shader_core_ctx::fetch() { // this code checks if this warp has finished executing and can be // reclaimed - if (m_warp[warp_id].hardware_done() && + if (m_warp[warp_id]->hardware_done() && !m_scoreboard->pendingWrites(warp_id) && - !m_warp[warp_id].done_exit()) { + !m_warp[warp_id]->done_exit()) { 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_threadState[tid].m_active == true) { m_threadState[tid].m_active = false; - unsigned cta_id = m_warp[warp_id].get_cta_id(); - register_cta_thread_exit(cta_id, &(m_thread[tid]->get_kernel())); + unsigned cta_id = m_warp[warp_id]->get_cta_id(); + if (m_thread[tid] == NULL) { + register_cta_thread_exit(cta_id, m_kernel); + } else { + register_cta_thread_exit(cta_id, + &(m_thread[tid]->get_kernel())); + } m_not_completed -= 1; m_active_threads.reset(tid); - assert(m_thread[tid] != NULL); did_exit = true; } } - if (did_exit) m_warp[warp_id].set_done_exit(); + if (did_exit) m_warp[warp_id]->set_done_exit(); --m_active_warps; assert(m_active_warps >= 0); } // this code fetches instructions from the i-cache or generates memory - // requests - if (!m_warp[warp_id].functional_done() && - !m_warp[warp_id].imiss_pending() && - m_warp[warp_id].ibuffer_empty()) { - address_type pc = m_warp[warp_id].get_pc(); + if (!m_warp[warp_id]->functional_done() && + !m_warp[warp_id]->imiss_pending() && + m_warp[warp_id]->ibuffer_empty()) { + address_type pc; + pc = m_warp[warp_id]->get_pc(); address_type ppc = pc + PROGRAM_MEM_START; unsigned nbytes = 16; unsigned offset_in_block = @@ -869,17 +952,22 @@ void shader_core_ctx::fetch() { warp_id, m_sid, m_tpc, m_memory_config, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle); std::list<cache_event> events; - enum cache_request_status status = m_L1I->access( - (new_addr_type)ppc, mf, - m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle, events); + enum cache_request_status status; + if (m_config->perfect_inst_const_cache) + status = HIT; + else + status = m_L1I->access( + (new_addr_type)ppc, mf, + m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle, events); + if (status == MISS) { m_last_warp_fetched = warp_id; - m_warp[warp_id].set_imiss_pending(); - m_warp[warp_id].set_last_fetch(m_gpu->gpu_sim_cycle); + m_warp[warp_id]->set_imiss_pending(); + m_warp[warp_id]->set_last_fetch(m_gpu->gpu_sim_cycle); } else if (status == HIT) { m_last_warp_fetched = warp_id; m_inst_fetch_buffer = ifetch_buffer_t(pc, nbytes, warp_id); - m_warp[warp_id].set_last_fetch(m_gpu->gpu_sim_cycle); + m_warp[warp_id]->set_last_fetch(m_gpu->gpu_sim_cycle); delete mf; } else { m_last_warp_fetched = warp_id; @@ -895,7 +983,7 @@ void shader_core_ctx::fetch() { m_L1I->cycle(); } -void shader_core_ctx::func_exec_inst(warp_inst_t &inst) { +void exec_shader_core_ctx::func_exec_inst(warp_inst_t &inst) { execute_warp_inst_t(inst); if (inst.is_load() || inst.is_store()) { inst.generate_mem_accesses(); @@ -911,27 +999,29 @@ void shader_core_ctx::issue_warp(register_set &pipe_reg_set, pipe_reg_set.get_free(m_config->sub_core_model, sch_id); assert(pipe_reg); - m_warp[warp_id].ibuffer_free(); + m_warp[warp_id]->ibuffer_free(); assert(next_inst->valid()); **pipe_reg = *next_inst; // static instruction information (*pipe_reg)->issue(active_mask, warp_id, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, - m_warp[warp_id].get_dynamic_warp_id(), + m_warp[warp_id]->get_dynamic_warp_id(), sch_id); // dynamic instruction information m_stats->shader_cycle_distro[2 + (*pipe_reg)->active_count()]++; func_exec_inst(**pipe_reg); + if (next_inst->op == BARRIER_OP) { - m_warp[warp_id].store_info_of_last_inst_at_barrier(*pipe_reg); - m_barriers.warp_reaches_barrier(m_warp[warp_id].get_cta_id(), warp_id, + m_warp[warp_id]->store_info_of_last_inst_at_barrier(*pipe_reg); + m_barriers.warp_reaches_barrier(m_warp[warp_id]->get_cta_id(), warp_id, const_cast<warp_inst_t *>(next_inst)); } else if (next_inst->op == MEMORY_BARRIER_OP) { - m_warp[warp_id].set_membar(); + m_warp[warp_id]->set_membar(); } updateSIMTStack(warp_id, *pipe_reg); + m_scoreboard->reserveRegisters(*pipe_reg); - m_warp[warp_id].set_next_pc(next_inst->pc + next_inst->isize); + m_warp[warp_id]->set_next_pc(next_inst->pc + next_inst->isize); } void shader_core_ctx::issue() { @@ -949,7 +1039,7 @@ void shader_core_ctx::issue() { //} } -shd_warp_t &scheduler_unit::warp(int i) { return (*m_warp)[i]; } +shd_warp_t &scheduler_unit::warp(int i) { return *((*m_warp)[i]); } /** * A general function to order things in a Loose Round Robin way. The simplist @@ -1068,6 +1158,17 @@ void scheduler_unit::cycle() { // units (as in Maxwell and // Pascal) + if (warp(warp_id).ibuffer_empty()) + SCHED_DPRINTF( + "Warp (warp_id %u, dynamic_warp_id %u) fails as ibuffer_empty\n", + (*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id()); + + if (warp(warp_id).waiting()) + SCHED_DPRINTF( + "Warp (warp_id %u, dynamic_warp_id %u) fails as waiting for " + "barrier\n", + (*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id()); + while (!warp(warp_id).waiting() && !warp(warp_id).ibuffer_empty() && (checked < max_issue) && (checked <= issued) && (issued < max_issue)) { @@ -1082,7 +1183,7 @@ void scheduler_unit::cycle() { bool valid = warp(warp_id).ibuffer_next_valid(); bool warp_inst_issued = false; unsigned pc, rpc; - m_simt_stack[warp_id]->get_pdom_stack_top_info(&pc, &rpc); + m_shader->get_pdom_stack_top_info(warp_id, pI, &pc, &rpc); SCHED_DPRINTF( "Warp (warp_id %u, dynamic_warp_id %u) has valid instruction (%s)\n", (*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id(), @@ -1105,8 +1206,10 @@ void scheduler_unit::cycle() { "Warp (warp_id %u, dynamic_warp_id %u) passes scoreboard\n", (*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id()); ready_inst = true; + const active_mask_t &active_mask = - m_simt_stack[warp_id]->get_active_mask(); + m_shader->get_active_mask(warp_id, pI); + assert(warp(warp_id).inst_in_pipeline()); if ((pI->op == LOAD_OP) || (pI->op == STORE_OP) || @@ -1126,19 +1229,25 @@ void scheduler_unit::cycle() { } } else { bool sp_pipe_avail = + (m_shader->m_config->gpgpu_num_sp_units > 0) && m_sp_out->has_free(m_shader->m_config->sub_core_model, m_id); bool sfu_pipe_avail = + (m_shader->m_config->gpgpu_num_sfu_units > 0) && m_sfu_out->has_free(m_shader->m_config->sub_core_model, m_id); - bool tensor_core_pipe_avail = m_tensor_core_out->has_free( - m_shader->m_config->sub_core_model, m_id); + bool tensor_core_pipe_avail = + (m_shader->m_config->gpgpu_num_tensor_core_units > 0) && + m_tensor_core_out->has_free( + m_shader->m_config->sub_core_model, m_id); bool dp_pipe_avail = + (m_shader->m_config->gpgpu_num_dp_units > 0) && m_dp_out->has_free(m_shader->m_config->sub_core_model, m_id); bool int_pipe_avail = + (m_shader->m_config->gpgpu_num_int_units > 0) && m_int_out->has_free(m_shader->m_config->sub_core_model, m_id); // This code need to be refactored if (pI->op != TENSOR_CORE_OP && pI->op != SFU_OP && - pI->op != DP_OP) { + pI->op != DP_OP && !(pI->op >= SPEC_UNIT_START_ID)) { bool execute_on_SP = false; bool execute_on_INT = false; @@ -1227,7 +1336,7 @@ void scheduler_unit::cycle() { } } else if ((pI->op == TENSOR_CORE_OP) && !(diff_exec_units && previous_issued_inst_exec_type == - exec_unit_type_t::SP)) { + exec_unit_type_t::TENSOR)) { if (tensor_core_pipe_avail) { m_shader->issue_warp(*m_tensor_core_out, pI, active_mask, warp_id, m_id); @@ -1236,7 +1345,30 @@ void scheduler_unit::cycle() { warp_inst_issued = true; previous_issued_inst_exec_type = exec_unit_type_t::TENSOR; } + } else if ((pI->op >= SPEC_UNIT_START_ID) && + !(diff_exec_units && + previous_issued_inst_exec_type == + exec_unit_type_t::SPECIALIZED)) { + unsigned spec_id = pI->op - SPEC_UNIT_START_ID; + assert(spec_id < m_shader->m_config->m_specialized_unit.size()); + register_set *spec_reg_set = m_spec_cores_out[spec_id]; + bool spec_pipe_avail = + (m_shader->m_config->m_specialized_unit[spec_id].num_units > + 0) && + spec_reg_set->has_free(m_shader->m_config->sub_core_model, + m_id); + + if (spec_pipe_avail) { + m_shader->issue_warp(*spec_reg_set, pI, active_mask, warp_id, + m_id); + issued++; + issued_inst = true; + warp_inst_issued = true; + previous_issued_inst_exec_type = + exec_unit_type_t::SPECIALIZED; + } } + } // end of else } else { SCHED_DPRINTF( @@ -1405,13 +1537,15 @@ void two_level_active_scheduler::order_warps() { swl_scheduler::swl_scheduler(shader_core_stats *stats, shader_core_ctx *shader, Scoreboard *scoreboard, simt_stack **simt, - std::vector<shd_warp_t> *warp, + std::vector<shd_warp_t *> *warp, register_set *sp_out, register_set *dp_out, register_set *sfu_out, register_set *int_out, register_set *tensor_core_out, + std::vector<register_set *> &spec_cores_out, register_set *mem_out, int id, char *config_string) : scheduler_unit(stats, shader, scoreboard, simt, warp, sp_out, dp_out, - sfu_out, int_out, tensor_core_out, mem_out, id) { + sfu_out, int_out, tensor_core_out, spec_cores_out, mem_out, + id) { unsigned m_prioritization_readin; int ret = sscanf(config_string, "warp_limiting:%d:%d", &m_prioritization_readin, &m_num_warps_to_limit); @@ -1533,7 +1667,7 @@ void shader_core_ctx::execute() { unsigned multiplier = m_fu[n]->clock_multiplier(); for (unsigned c = 0; c < multiplier; c++) m_fu[n]->cycle(); m_fu[n]->active_lanes_in_pipeline(); - enum pipeline_stage_name_t issue_port = m_issue_port[n]; + unsigned issue_port = m_issue_port[n]; register_set &issue_inst = m_pipeline_reg[issue_port]; warp_inst_t **ready_reg = issue_inst.get_ready(); if (issue_inst.has_ready() && m_fu[n]->can_issue(**ready_reg)) { @@ -1579,8 +1713,8 @@ void ldst_unit::get_L1T_sub_stats(struct cache_sub_stats &css) const { void shader_core_ctx::warp_inst_complete(const warp_inst_t &inst) { #if 0 - printf("[warp_inst_complete] uid=%u core=%u warp=%u pc=%#x @ time=%llu issued@%llu\n", - inst.get_uid(), m_sid, inst.warp_id(), inst.pc, gpu_tot_sim_cycle + gpu_sim_cycle, inst.get_issue_cycle()); + printf("[warp_inst_complete] uid=%u core=%u warp=%u pc=%#x @ time=%llu \n", + inst.get_uid(), m_sid, inst.warp_id(), inst.pc, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle); #endif if (inst.op_pipe == SP__OP) @@ -1635,7 +1769,7 @@ void shader_core_ctx::writeback() { m_operand_collector.writeback(*pipe_reg); unsigned warp_id = pipe_reg->warp_id(); m_scoreboard->releaseRegisters(pipe_reg); - m_warp[warp_id].dec_inst_in_pipeline(); + m_warp[warp_id]->dec_inst_in_pipeline(); warp_inst_complete(*pipe_reg); m_gpu->gpu_sim_insn_last_update_sid = m_sid; m_gpu->gpu_sim_insn_last_update = m_gpu->gpu_sim_cycle; @@ -1651,6 +1785,8 @@ bool ldst_unit::shared_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { if (inst.space.get_type() != shared_space) return true; + if (inst.active_count() == 0) return true; + if (inst.has_dispatch_delay()) { m_stats->gpgpu_n_shmem_bank_access[m_sid]++; } @@ -1852,7 +1988,19 @@ bool ldst_unit::constant_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail, (inst.space.get_type() != param_space_kernel))) return true; if (inst.active_count() == 0) return true; - mem_stage_stall_type fail = process_memory_access_queue(m_L1C, inst); + + mem_stage_stall_type fail; + if (m_config->perfect_inst_const_cache) { + fail = NO_RC_FAIL; + while (inst.accessq_count() > 0) inst.accessq_pop_back(); + if (inst.is_load()) { + for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) + if (inst.out[r] > 0) m_pending_writes[inst.warp_id()][inst.out[r]]--; + } + } else { + fail = process_memory_access_queue(m_L1C, inst); + } + if (fail != NO_RC_FAIL) { rc_fail = fail; // keep other fails if this didn't fail. fail_type = C_MEM; @@ -1885,7 +2033,8 @@ bool ldst_unit::memory_cycle(warp_inst_t &inst, (inst.space.get_type() != param_space_local))) return true; if (inst.active_count() == 0) return true; - assert(!inst.accessq_empty()); + if (inst.accessq_empty()) return true; + mem_stage_stall_type stall_cond = NO_RC_FAIL; const mem_access_t &access = inst.accessq_back(); @@ -2027,6 +2176,13 @@ void dp_unit::active_lanes_in_pipeline() { m_core->incfuactivelanes_stat(active_count); m_core->incfumemactivelanes_stat(active_count); } +void specialized_unit::active_lanes_in_pipeline() { + unsigned active_count = pipelined_simd_unit::get_active_lanes_in_pipeline(); + assert(active_count <= m_core->get_config()->warp_size); + m_core->incspactivelanes_stat(active_count); + m_core->incfuactivelanes_stat(active_count); + m_core->incfumemactivelanes_stat(active_count); +} void int_unit::active_lanes_in_pipeline() { unsigned active_count = pipelined_simd_unit::get_active_lanes_in_pipeline(); @@ -2057,6 +2213,15 @@ sp_unit::sp_unit(register_set *result_port, const shader_core_config *config, m_name = "SP "; } +specialized_unit::specialized_unit(register_set *result_port, + const shader_core_config *config, + shader_core_ctx *core, unsigned supported_op, + char *unit_name, unsigned latency) + : pipelined_simd_unit(result_port, config, latency, core) { + m_name = unit_name; + m_supported_op = supported_op; +} + dp_unit::dp_unit(register_set *result_port, const shader_core_config *config, shader_core_ctx *core) : pipelined_simd_unit(result_port, config, config->max_dp_latency, core) { @@ -2085,6 +2250,14 @@ void dp_unit ::issue(register_set &source_reg) { pipelined_simd_unit::issue(source_reg); } +void specialized_unit ::issue(register_set &source_reg) { + warp_inst_t **ready_reg = source_reg.get_ready(); + // m_core->incexecstat((*ready_reg)); + (*ready_reg)->op_pipe = SPECIALIZED__OP; + m_core->incsp_stat(m_core->get_config()->warp_size, (*ready_reg)->latency); + pipelined_simd_unit::issue(source_reg); +} + void int_unit ::issue(register_set &source_reg) { warp_inst_t **ready_reg = source_reg.get_ready(); // m_core->incexecstat((*ready_reg)); @@ -2316,10 +2489,11 @@ void ldst_unit::writeback() { case 3: // global/local if (m_next_global) { m_next_wb = m_next_global->get_inst(); - if (m_next_global->isatomic()) + if (m_next_global->isatomic()) { m_core->decrement_atomic_count( m_next_global->get_wid(), m_next_global->get_access_warp_mask().count()); + } delete m_next_global; m_next_global = NULL; serviced_client = next_client; @@ -2376,7 +2550,8 @@ inst->space.get_type() != shared_space) { unsigned warp_id = inst->warp_id(); */ void ldst_unit::cycle() { writeback(); - m_operand_collector->step(); + for (int i = 0; i < m_config->reg_file_port_throughput; ++i) + m_operand_collector->step(); for (unsigned stage = 0; (stage + 1) < m_pipeline_depth; stage++) if (m_pipeline_reg[stage]->empty() && !m_pipeline_reg[stage + 1]->empty()) move_warp(m_pipeline_reg[stage], m_pipeline_reg[stage + 1]); @@ -2512,6 +2687,7 @@ void shader_core_ctx::register_cta_thread_exit(unsigned cta_num, m_cta_status[cta_num]--; if (!m_cta_status[cta_num]) { // Increment the completed CTAs + m_stats->ctas_completed++; m_gpu->inc_completed_cta(); m_n_active_cta--; m_barriers.deallocate_barrier(cta_num); @@ -2578,6 +2754,7 @@ void gpgpu_sim::shader_print_runtime_stat(FILE *fout) { void gpgpu_sim::shader_print_scheduler_stat(FILE *fout, bool print_dynamic_info) const { + fprintf(fout, "ctas_completed %d, ", m_shader_stats->ctas_completed); // Print out the stats from the sampling shader core const unsigned scheduler_sampling_core = m_shader_config->gpgpu_warp_issue_shader; @@ -2954,7 +3131,7 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, } 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); + if (!m_warp[i]->ibuffer_empty()) m_warp[i]->print_ibuffer(fout); } fprintf(fout, "\n"); display_simt_state(fout, mask); @@ -3095,11 +3272,11 @@ unsigned int shader_core_config::max_cta(const kernel_info_t &k) const { switch (adaptive_cache_config) { case FIXED: break; - case VOLTA: { + case ADAPTIVE_VOLTA: { // For Volta, we assign the remaining shared memory to L1 cache // For more info about adaptive cache, see // https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory-7-x - assert(gpgpu_shmem_size == 98304); // Volta has 96 KB shared + // assert(gpgpu_shmem_size == 98304); //Volta has 96 KB shared // To Do: make it flexible and not tuned to 9KB share memory unsigned max_assoc = m_L1D_config.get_max_assoc(); @@ -3184,8 +3361,10 @@ void shader_core_ctx::cycle() { execute(); read_operands(); issue(); - decode(); - fetch(); + for (int i = 0; i < m_config->inst_fetch_throughput; ++i) { + decode(); + fetch(); + } } // Flushes all content of the cache to memory @@ -3234,28 +3413,34 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() { ///// wavefront allocator from booksim... ---> // Loop through diagonals of request matrix + // printf("####\n"); for (int p = 0; p < _square; ++p) { - output = (_pri + p) % _square; + output = (_pri + p) % _outputs; // Step through the current diagonal for (input = 0; input < _inputs; ++input) { assert(input < _inputs); assert(output < _outputs); if ((output < _outputs) && (_inmatch[input] == -1) && - (_outmatch[output] == -1) && + //( _outmatch[output] == -1 ) && //allow OC to read multiple reg + // banks at the same cycle (_request[input][output] /*.label != -1*/)) { // Grant! _inmatch[input] = output; _outmatch[output] = input; + // printf("Register File: granting bank %d to OC %d, schedid %d, warpid + // %d, Regid %d\n", input, output, (m_queue[input].front()).get_sid(), + // (m_queue[input].front()).get_wid(), + // (m_queue[input].front()).get_reg()); } - output = (output + 1) % _square; + output = (output + 1) % _outputs; } } // Round-robin the priority diagonal - _pri = (_pri + 1) % _square; + _pri = (_pri + 1) % _outputs; /// <--- end code from booksim @@ -3466,7 +3651,7 @@ bool shader_core_ctx::check_if_non_released_reduction_barrier( bool non_released_barrier_reduction = false; bool warp_stucked_at_barrier = warp_waiting_at_barrier(warp_id); bool single_inst_in_pipeline = - (m_warp[warp_id].num_issued_inst_in_pipeline() == 1); + (m_warp[warp_id]->num_issued_inst_in_pipeline() == 1); non_released_barrier_reduction = single_inst_in_pipeline and warp_stucked_at_barrier and bar_red_op; printf("non_released_barrier_reduction=%u\n", non_released_barrier_reduction); @@ -3478,9 +3663,18 @@ bool shader_core_ctx::warp_waiting_at_barrier(unsigned warp_id) const { } bool shader_core_ctx::warp_waiting_at_mem_barrier(unsigned warp_id) { - if (!m_warp[warp_id].get_membar()) return false; + if (!m_warp[warp_id]->get_membar()) return false; if (!m_scoreboard->pendingWrites(warp_id)) { - m_warp[warp_id].clear_membar(); + m_warp[warp_id]->clear_membar(); + if (m_gpu->get_config().flush_l1()) { + // Mahmoud fixed this on Nov 2019 + // Invalidate L1 cache + // Based on Nvidia Doc, at MEM barrier, we have to + //(1) wait for all pending writes till they are acked + //(2) invalidate L1 cache to ensure coherence and avoid reading stall data + cache_invalidate(); + // TO DO: you need to stall the SM for 5k cycles. + } return false; } return true; @@ -3497,8 +3691,8 @@ void shader_core_ctx::set_max_cta(const kernel_info_t &kernel) { } void shader_core_ctx::decrement_atomic_count(unsigned wid, unsigned n) { - assert(m_warp[wid].get_n_atomic() >= n); - m_warp[wid].dec_n_atomic(n); + assert(m_warp[wid]->get_n_atomic() >= n); + m_warp[wid]->dec_n_atomic(n); } void shader_core_ctx::broadcast_barrier_reduction(unsigned cta_id, @@ -3507,7 +3701,7 @@ void shader_core_ctx::broadcast_barrier_reduction(unsigned cta_id, for (unsigned i = 0; i < m_config->max_warps_per_shader; i++) { if (warps.test(i)) { const warp_inst_t *inst = - m_warp[i].restore_info_of_last_inst_at_barrier(); + m_warp[i]->restore_info_of_last_inst_at_barrier(); const_cast<warp_inst_t *>(inst)->broadcast_barrier_reduction( inst->get_active_mask()); } @@ -3534,7 +3728,7 @@ void shader_core_ctx::store_ack(class mem_fetch *mf) { assert(mf->get_type() == WRITE_ACK || (m_config->gpgpu_perfect_mem && mf->get_is_write())); unsigned warp_id = mf->get_wid(); - m_warp[warp_id].dec_store_req(); + m_warp[warp_id]->dec_store_req(); } void shader_core_ctx::print_cache_stats(FILE *fp, unsigned &dl1_accesses, @@ -3910,6 +4104,16 @@ void opndcoll_rfu_t::collector_unit_t::dispatch() { for (unsigned i = 0; i < MAX_REG_OPERANDS * 2; i++) m_src_op[i].reset(); } +void exec_simt_core_cluster::create_shader_core_ctx() { + m_core = new shader_core_ctx *[m_config->n_simt_cores_per_cluster]; + for (unsigned i = 0; i < m_config->n_simt_cores_per_cluster; i++) { + unsigned sid = m_config->cid_to_sid(i, m_cluster_id); + m_core[i] = new exec_shader_core_ctx(m_gpu, this, sid, m_cluster_id, + m_config, m_mem_config, m_stats); + m_core_sim_order.push_back(i); + } +} + simt_core_cluster::simt_core_cluster(class gpgpu_sim *gpu, unsigned cluster_id, const shader_core_config *config, const memory_config *mem_config, @@ -3922,13 +4126,7 @@ simt_core_cluster::simt_core_cluster(class gpgpu_sim *gpu, unsigned cluster_id, m_gpu = gpu; m_stats = stats; m_memory_stats = mstats; - m_core = new shader_core_ctx *[config->n_simt_cores_per_cluster]; - for (unsigned i = 0; i < config->n_simt_cores_per_cluster; i++) { - unsigned sid = m_config->cid_to_sid(i, m_cluster_id); - m_core[i] = new shader_core_ctx(gpu, this, sid, m_cluster_id, config, - mem_config, stats); - m_core_sim_order.push_back(i); - } + m_mem_config = mem_config; } void simt_core_cluster::core_cycle() { @@ -4240,9 +4438,10 @@ void simt_core_cluster::get_L1T_sub_stats(struct cache_sub_stats &css) const { css = total_css; } -void shader_core_ctx::checkExecutionStatusAndUpdate(warp_inst_t &inst, - unsigned t, unsigned tid) { - if (inst.isatomic()) m_warp[inst.warp_id()].inc_n_atomic(); +void exec_shader_core_ctx::checkExecutionStatusAndUpdate(warp_inst_t &inst, + unsigned t, + unsigned tid) { + if (inst.isatomic()) m_warp[inst.warp_id()]->inc_n_atomic(); if (inst.space.is_local() && (inst.is_load() || inst.is_store())) { new_addr_type localaddrs[MAX_ACCESSES_PER_INSN_PER_THREAD]; unsigned num_addrs; @@ -4253,8 +4452,8 @@ void shader_core_ctx::checkExecutionStatusAndUpdate(warp_inst_t &inst, inst.set_addr(t, (new_addr_type *)localaddrs, num_addrs); } if (ptx_thread_done(tid)) { - m_warp[inst.warp_id()].set_completed(t); - m_warp[inst.warp_id()].ibuffer_flush(); + m_warp[inst.warp_id()]->set_completed(t); + m_warp[inst.warp_id()]->ibuffer_flush(); } // PC-Histogram Update diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index 1af35cf..6481790 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -79,7 +79,8 @@ enum exec_unit_type_t { MEM = 3, DP = 4, INT = 5, - TENSOR = 6 + TENSOR = 6, + SPECIALIZED = 7 }; class thread_ctx_t { @@ -167,7 +168,7 @@ class shd_warp_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; } + virtual address_type get_pc() const { return m_next_pc; } void set_next_pc(address_type pc) { m_next_pc = pc; } void store_info_of_last_inst_at_barrier(const warp_inst_t *pI) { @@ -237,6 +238,7 @@ class shd_warp_t { unsigned get_dynamic_warp_id() const { return m_dynamic_warp_id; } unsigned get_warp_id() const { return m_warp_id; } + class shader_core_ctx * get_shader() { return m_shader; } private: static const unsigned IBUFFER_SIZE = 2; class shader_core_ctx *m_shader; @@ -326,9 +328,10 @@ class scheduler_unit { // this can be copied freely, so can be used in std public: scheduler_unit(shader_core_stats *stats, shader_core_ctx *shader, Scoreboard *scoreboard, simt_stack **simt, - std::vector<shd_warp_t> *warp, register_set *sp_out, + std::vector<shd_warp_t *> *warp, register_set *sp_out, register_set *dp_out, register_set *sfu_out, register_set *int_out, register_set *tensor_core_out, + std::vector<register_set *> &spec_cores_out, register_set *mem_out, int id) : m_supervised_warps(), m_stats(stats), @@ -341,6 +344,7 @@ class scheduler_unit { // this can be copied freely, so can be used in std m_sfu_out(sfu_out), m_int_out(int_out), m_tensor_core_out(tensor_core_out), + m_spec_cores_out(spec_cores_out), m_mem_out(mem_out), m_id(id) {} virtual ~scheduler_unit() {} @@ -415,13 +419,14 @@ class scheduler_unit { // this can be copied freely, so can be used in std Scoreboard *m_scoreboard; simt_stack **m_simt_stack; // warp_inst_t** m_pipeline_reg; - std::vector<shd_warp_t> *m_warp; + std::vector<shd_warp_t *> *m_warp; register_set *m_sp_out; register_set *m_dp_out; register_set *m_sfu_out; register_set *m_int_out; register_set *m_tensor_core_out; register_set *m_mem_out; + std::vector<register_set *> &m_spec_cores_out; int m_id; }; @@ -430,12 +435,14 @@ class lrr_scheduler : public scheduler_unit { public: lrr_scheduler(shader_core_stats *stats, shader_core_ctx *shader, Scoreboard *scoreboard, simt_stack **simt, - std::vector<shd_warp_t> *warp, register_set *sp_out, + std::vector<shd_warp_t *> *warp, register_set *sp_out, register_set *dp_out, register_set *sfu_out, register_set *int_out, register_set *tensor_core_out, + std::vector<register_set *> &spec_cores_out, register_set *mem_out, int id) : scheduler_unit(stats, shader, scoreboard, simt, warp, sp_out, dp_out, - sfu_out, int_out, tensor_core_out, mem_out, id) {} + sfu_out, int_out, tensor_core_out, spec_cores_out, + mem_out, id) {} virtual ~lrr_scheduler() {} virtual void order_warps(); virtual void done_adding_supervised_warps() { @@ -447,12 +454,14 @@ class gto_scheduler : public scheduler_unit { public: gto_scheduler(shader_core_stats *stats, shader_core_ctx *shader, Scoreboard *scoreboard, simt_stack **simt, - std::vector<shd_warp_t> *warp, register_set *sp_out, + std::vector<shd_warp_t *> *warp, register_set *sp_out, register_set *dp_out, register_set *sfu_out, register_set *int_out, register_set *tensor_core_out, + std::vector<register_set *> &spec_cores_out, register_set *mem_out, int id) : scheduler_unit(stats, shader, scoreboard, simt, warp, sp_out, dp_out, - sfu_out, int_out, tensor_core_out, mem_out, id) {} + sfu_out, int_out, tensor_core_out, spec_cores_out, + mem_out, id) {} virtual ~gto_scheduler() {} virtual void order_warps(); virtual void done_adding_supervised_warps() { @@ -464,12 +473,14 @@ class oldest_scheduler : public scheduler_unit { public: oldest_scheduler(shader_core_stats *stats, shader_core_ctx *shader, Scoreboard *scoreboard, simt_stack **simt, - std::vector<shd_warp_t> *warp, register_set *sp_out, + std::vector<shd_warp_t *> *warp, register_set *sp_out, register_set *dp_out, register_set *sfu_out, register_set *int_out, register_set *tensor_core_out, + std::vector<register_set *> &spec_cores_out, register_set *mem_out, int id) : scheduler_unit(stats, shader, scoreboard, simt, warp, sp_out, dp_out, - sfu_out, int_out, tensor_core_out, mem_out, id) {} + sfu_out, int_out, tensor_core_out, spec_cores_out, + mem_out, id) {} virtual ~oldest_scheduler() {} virtual void order_warps(); virtual void done_adding_supervised_warps() { @@ -481,13 +492,15 @@ class two_level_active_scheduler : public scheduler_unit { public: two_level_active_scheduler(shader_core_stats *stats, shader_core_ctx *shader, Scoreboard *scoreboard, simt_stack **simt, - std::vector<shd_warp_t> *warp, + std::vector<shd_warp_t *> *warp, register_set *sp_out, register_set *dp_out, register_set *sfu_out, register_set *int_out, register_set *tensor_core_out, + std::vector<register_set *> &spec_cores_out, register_set *mem_out, int id, char *config_str) : scheduler_unit(stats, shader, scoreboard, simt, warp, sp_out, dp_out, - sfu_out, int_out, tensor_core_out, mem_out, id), + sfu_out, int_out, tensor_core_out, spec_cores_out, + mem_out, id), m_pending_warps() { unsigned inner_level_readin; unsigned outer_level_readin; @@ -530,9 +543,10 @@ class swl_scheduler : public scheduler_unit { public: swl_scheduler(shader_core_stats *stats, shader_core_ctx *shader, Scoreboard *scoreboard, simt_stack **simt, - std::vector<shd_warp_t> *warp, register_set *sp_out, + std::vector<shd_warp_t *> *warp, register_set *sp_out, register_set *dp_out, register_set *sfu_out, register_set *int_out, register_set *tensor_core_out, + std::vector<register_set *> &spec_cores_out, register_set *mem_out, int id, char *config_string); virtual ~swl_scheduler() {} virtual void order_warps(); @@ -1211,6 +1225,24 @@ class sp_unit : public pipelined_simd_unit { virtual void issue(register_set &source_reg); }; +class specialized_unit : public pipelined_simd_unit { + public: + specialized_unit(register_set *result_port, const shader_core_config *config, + shader_core_ctx *core, unsigned supported_op, + char *unit_name, unsigned latency); + virtual bool can_issue(const warp_inst_t &inst) const { + if (inst.op != m_supported_op) { + return false; + } + return pipelined_simd_unit::can_issue(inst); + } + virtual void active_lanes_in_pipeline(); + virtual void issue(register_set &source_reg); + + private: + unsigned m_supported_op; +}; + class simt_core_cluster; class shader_memory_interface; class shader_core_mem_fetch_allocator; @@ -1361,6 +1393,16 @@ const char *const pipeline_stage_name_decode[] = { "OC_EX_SFU", "OC_EX_MEM", "EX_WB", "ID_OC_TENSOR_CORE", "OC_EX_TENSOR_CORE", "N_PIPELINE_STAGES"}; +struct specialized_unit_params { + unsigned latency; + unsigned num_units; + unsigned id_oc_spec_reg_width; + unsigned oc_ex_spec_reg_width; + char name[20]; + unsigned ID_OC_SPEC_ID; + unsigned OC_EX_SPEC_ID; +}; + class shader_core_config : public core_config { public: shader_core_config(gpgpu_context *ctx) : core_config(ctx) { @@ -1419,6 +1461,24 @@ class shader_core_config : public core_config { gpgpu_cache_texl1_linesize = m_L1T_config.get_line_sz(); gpgpu_cache_constl1_linesize = m_L1C_config.get_line_sz(); m_valid = true; + + m_specialized_unit_num = 0; + // parse the specialized units + for (unsigned i = 0; i < SPECIALIZED_UNIT_NUM; ++i) { + unsigned enabled; + specialized_unit_params sparam; + sscanf(specialized_unit_string[i], "%u,%u,%u,%u,%u,%s", &enabled, + &sparam.num_units, &sparam.latency, &sparam.id_oc_spec_reg_width, + &sparam.oc_ex_spec_reg_width, sparam.name); + + if (enabled) { + m_specialized_unit.push_back(sparam); + strncpy(m_specialized_unit.back().name, sparam.name, + sizeof(m_specialized_unit.back().name)); + m_specialized_unit_num += sparam.num_units; + } else + break; // we only accept continuous specialized_units, i.e., 1,2,3,4 + } } void reg_options(class OptionParser *opp); unsigned max_cta(const kernel_info_t &k) const; @@ -1531,7 +1591,14 @@ class shader_core_config : public core_config { // Jin: concurrent kernel on sm bool gpgpu_concurrent_kernel_sm; - bool adpative_volta_cache_config; + bool perfect_inst_const_cache; + unsigned inst_fetch_throughput; + unsigned reg_file_port_throughput; + + // specialized unit config strings + char *specialized_unit_string[SPECIALIZED_UNIT_NUM]; + mutable std::vector<specialized_unit_params> m_specialized_unit; + unsigned m_specialized_unit_num; }; struct shader_core_stats_pod { @@ -1602,6 +1669,7 @@ struct shader_core_stats_pod { unsigned *single_issue_nums; unsigned *dual_issue_nums; + unsigned ctas_completed; // memory access classification int gpgpu_n_mem_read_local; int gpgpu_n_mem_write_local; @@ -1715,6 +1783,7 @@ class shader_core_stats : public shader_core_stats_pod { dual_issue_nums = (unsigned *)calloc(config->gpgpu_num_sched_per_core, sizeof(unsigned)); + ctas_completed = 0; n_simt_to_mem = (long *)calloc(config->num_shader(), sizeof(long)); n_mem_to_simt = (long *)calloc(config->num_shader(), sizeof(long)); @@ -1860,9 +1929,9 @@ class shader_core_ctx : public core_t { // modifiers void mem_instruction_stats(const warp_inst_t &inst); void decrement_atomic_count(unsigned wid, unsigned n); - void inc_store_req(unsigned warp_id) { m_warp[warp_id].inc_store_req(); } + void inc_store_req(unsigned warp_id) { m_warp[warp_id]->inc_store_req(); } void dec_inst_in_pipeline(unsigned warp_id) { - m_warp[warp_id].dec_inst_in_pipeline(); + m_warp[warp_id]->dec_inst_in_pipeline(); } // also used in writeback() void store_ack(class mem_fetch *mf); bool warp_waiting_at_mem_barrier(unsigned warp_id); @@ -2041,7 +2110,7 @@ class shader_core_ctx : public core_t { } bool check_if_non_released_reduction_barrier(warp_inst_t &inst); - private: + protected: unsigned inactive_lanes_accesses_sfu(unsigned active_count, double latency) { return (((32 - active_count) >> 1) * latency) + (((32 - active_count) >> 3) * latency) + @@ -2053,10 +2122,6 @@ class shader_core_ctx : public core_t { } int test_res_bus(int latency); - void init_warps(unsigned cta_id, unsigned start_thread, unsigned end_thread, - unsigned ctaid, int cta_size, unsigned kernel_id); - virtual void checkExecutionStatusAndUpdate(warp_inst_t &inst, unsigned t, - unsigned tid); address_type next_pc(int tid) const; void fetch(); void register_cta_thread_exit(unsigned cta_num, kernel_info_t *kernel); @@ -2067,10 +2132,38 @@ class shader_core_ctx : public core_t { friend class scheduler_unit; // this is needed to use private issue warp. friend class TwoLevelScheduler; friend class LooseRoundRobbinScheduler; - void issue_warp(register_set &warp, const warp_inst_t *pI, + virtual void issue_warp(register_set &warp, const warp_inst_t *pI, const active_mask_t &active_mask, unsigned warp_id, unsigned sch_id); - void func_exec_inst(warp_inst_t &inst); + + void create_front_pipeline(); + void create_schedulers(); + void create_exec_pipeline(); + + // pure virtual methods implemented based on the current execution mode + // (execution-driven vs trace-driven) + virtual void init_warps(unsigned cta_id, unsigned start_thread, + unsigned end_thread, unsigned ctaid, int cta_size, + kernel_info_t &kernel); + virtual void checkExecutionStatusAndUpdate(warp_inst_t &inst, unsigned t, + unsigned tid) = 0; + virtual void func_exec_inst(warp_inst_t &inst) = 0; + + virtual unsigned sim_init_thread(kernel_info_t &kernel, + ptx_thread_info **thread_info, int sid, + unsigned tid, unsigned threads_left, + unsigned num_threads, core_t *core, + unsigned hw_cta_id, unsigned hw_warp_id, + gpgpu_t *gpu) = 0; + + virtual void create_shd_warp() = 0; + + virtual const warp_inst_t *get_next_inst(unsigned warp_id, + address_type pc) = 0; + virtual void get_pdom_stack_top_info(unsigned warp_id, const warp_inst_t *pI, + unsigned *pc, unsigned *rpc) = 0; + virtual const active_mask_t &get_active_mask(unsigned warp_id, + const warp_inst_t *pI) = 0; // Returns numbers of addresses in translated_addrs unsigned translate_local_memaddr(address_type localaddr, unsigned tid, @@ -2086,6 +2179,7 @@ class shader_core_ctx : public core_t { // used in display_pipeline(): void dump_warp_state(FILE *fout) const; void print_stage(unsigned int stage, FILE *fout) const; + unsigned long long m_last_inst_gpu_sim_cycle; unsigned long long m_last_inst_gpu_tot_sim_cycle; @@ -2120,13 +2214,14 @@ class shader_core_ctx : public core_t { int m_last_warp_fetched; // decode/dispatch - std::vector<shd_warp_t> m_warp; // per warp information array + std::vector<shd_warp_t *> m_warp; // per warp information array barrier_set_t m_barriers; ifetch_buffer_t m_inst_fetch_buffer; std::vector<register_set> m_pipeline_reg; Scoreboard *m_scoreboard; opndcoll_rfu_t m_operand_collector; int m_active_warps; + std::vector<register_set *> m_specilized_dispatch_reg; // schedule std::vector<scheduler_unit *> schedulers; @@ -2136,8 +2231,8 @@ class shader_core_ctx : public core_t { // execute unsigned m_num_function_units; - std::vector<pipeline_stage_name_t> m_dispatch_port; - std::vector<pipeline_stage_name_t> m_issue_port; + std::vector<unsigned> m_dispatch_port; + std::vector<unsigned> m_issue_port; std::vector<simd_function_unit *> m_fu; // stallable pipelines should be last in this array ldst_unit *m_ldst_unit; @@ -2170,6 +2265,38 @@ class shader_core_ctx : public core_t { std::map<unsigned int, unsigned int> m_occupied_cta_to_hwtid; }; +class exec_shader_core_ctx : public shader_core_ctx { + public: + exec_shader_core_ctx(class gpgpu_sim *gpu, class simt_core_cluster *cluster, + unsigned shader_id, unsigned tpc_id, + const shader_core_config *config, + const memory_config *mem_config, + shader_core_stats *stats) + : shader_core_ctx(gpu, cluster, shader_id, tpc_id, config, mem_config, + stats) { + create_front_pipeline(); + create_shd_warp(); + create_schedulers(); + create_exec_pipeline(); + } + + virtual void checkExecutionStatusAndUpdate(warp_inst_t &inst, unsigned t, + unsigned tid); + virtual void func_exec_inst(warp_inst_t &inst); + virtual unsigned sim_init_thread(kernel_info_t &kernel, + ptx_thread_info **thread_info, int sid, + unsigned tid, unsigned threads_left, + unsigned num_threads, core_t *core, + unsigned hw_cta_id, unsigned hw_warp_id, + gpgpu_t *gpu); + virtual void create_shd_warp(); + virtual const warp_inst_t *get_next_inst(unsigned warp_id, address_type pc); + virtual void get_pdom_stack_top_info(unsigned warp_id, const warp_inst_t *pI, + unsigned *pc, unsigned *rpc); + virtual const active_mask_t &get_active_mask(unsigned warp_id, + const warp_inst_t *pI); +}; + class simt_core_cluster { public: simt_core_cluster(class gpgpu_sim *gpu, unsigned cluster_id, @@ -2217,20 +2344,36 @@ class simt_core_cluster { void get_icnt_stats(long &n_simt_to_mem, long &n_mem_to_simt) const; float get_current_occupancy(unsigned long long &active, unsigned long long &total) const; + virtual void create_shader_core_ctx() = 0; - private: + protected: unsigned m_cluster_id; gpgpu_sim *m_gpu; const shader_core_config *m_config; shader_core_stats *m_stats; memory_stats_t *m_memory_stats; shader_core_ctx **m_core; + const memory_config *m_mem_config; unsigned m_cta_issue_next_core; std::list<unsigned> m_core_sim_order; std::list<mem_fetch *> m_response_fifo; }; +class exec_simt_core_cluster : public simt_core_cluster { + public: + exec_simt_core_cluster(class gpgpu_sim *gpu, unsigned cluster_id, + const shader_core_config *config, + const memory_config *mem_config, + class shader_core_stats *stats, + class memory_stats_t *mstats) + : simt_core_cluster(gpu, cluster_id, config, mem_config, stats, mstats) { + create_shader_core_ctx(); + } + + virtual void create_shader_core_ctx(); +}; + class shader_memory_interface : public mem_fetch_interface { public: shader_memory_interface(shader_core_ctx *core, simt_core_cluster *cluster) { diff --git a/src/gpgpusim_entrypoint.cc b/src/gpgpusim_entrypoint.cc index b7b7f34..f4287d8 100644 --- a/src/gpgpusim_entrypoint.cc +++ b/src/gpgpusim_entrypoint.cc @@ -219,7 +219,7 @@ gpgpu_sim *gpgpu_context::gpgpu_ptx_sim_init_perf() { the_gpgpusim->g_the_gpu_config->init(); the_gpgpusim->g_the_gpu = - new gpgpu_sim(*(the_gpgpusim->g_the_gpu_config), this); + new exec_gpgpu_sim(*(the_gpgpusim->g_the_gpu_config), this); the_gpgpusim->g_stream_manager = new stream_manager( (the_gpgpusim->g_the_gpu), func_sim->g_cuda_launch_blocking); diff --git a/travis.sh b/travis.sh new file mode 100755 index 0000000..bbdd19a --- /dev/null +++ b/travis.sh @@ -0,0 +1,24 @@ +if [ ! -n "$CUDA_INSTALL_PATH" ]; then + echo "ERROR ** Install CUDA Toolkit and set CUDA_INSTALL_PATH."; + exit; +fi + +if [ ! -n "$CONFIG" ]; then + echo "ERROR ** set the CONFIG env variable to one of those found in ./accel-sim-framework/util/job_launching/configs/define-standard-cfgs.yml"; + exit; +fi + +if [ ! -n "$GPUAPPS_ROOT" ]; then + echo "ERROR ** GPUAPPS_ROOT to a location where the apps have been compiled"; + exit; +fi + +export PATH=$CUDA_INSTALL_PATH/bin:$PATH +source ./setup_environment +make -j + +pip install psutil +rm -rf accel-sim-framework +git clone https://github.com/accel-sim/accel-sim-framework.git +./accel-sim-framework/util/job_launching/run_simulations.py -C $CONFIG -B rodinia_2.0-ft -N regress -l local +./accel-sim-framework/util/job_launching/monitor_func_test.py -v -N regress -j procman |
