| Date | Description |
| 20-Jan-14 | Original posting |
Your assignment is to optimize matrix multiplication for NVIDIA's Fermi GPU. You'll measure and report on performance on the Dirac platform located at NERSC. Your starting point is a naive CUDA implementation, plus, for comparison purposes, a high performance multicore implementation. If working in a group of 3, the requirements for this assignment will be somewhat more ambitious than for groups of 2.
Try to make your code go as fast as you can. In the spirit of friendly competition, post your performance results to the A2 Moodle forum. We will post a summary of the class' results on-line.
The provided starter code is available via svn, as described on the following web page:
http://www-cse.ucsd.edu/classes/wi14/cse260-a/HW/A2/StarterCode.html
The performance goals of this assignment depend on whether you are working in a team of two or a team of three.
To realize these performance goals, you may need to explore the optimizations in the following SC '08 paper by Volkov and Demmel: Benchmarking GPUs to tune dense linear algebra. Since the implementation was designed for a pre-Fermi device, (device capability < 2.0), the required optimizations (or the details, i.e. tuning parameters) may differ on Fermi.
http://www-cse.ucsd.edu/classes/wi14/cse260-a/HW/A2/WhatToTurnin.html
Specific report requirements. Your report must present certain measurements, but feel free to add others if they illuminate your understanding of high performance matrix multiplication on Fermi. Plot the speedup of your optimized algorithm against the two provided codes: naive CUDA and multicore. For each GPU data point, use the optimal blocking factor, and report the blocking factors you used in a table, along with the GigaFLOP rates for the naive optimized implementation and multicore implementation. When more than one blocking factor led to the same performance (differing less than 1%), identify all thread block factors that yielded that performance.
For n=1024, plot performance (GigaFLOPS/sec) as a function of the thread block geometry, noting the optimal value. Is there a "sweet spot" (or spots) that minimizes the running time? Explain how the optimal value of the thread blocking factor relates to performance
Since you must report performance for n=256, 512, 1024 and 2048, it follows that your code must run correctly for these cases.Your grade will depend on 3 factors: performance attained by your implementation; correctness and explanation and insight into how you realized your reported performance. In determining your grade for the assignment, explanations and insight will be emphasized somewhat more heavily than performance itself, unless there was little improvement in performance over the provided naive code.
Instructions for setting up your environment on Dirac and using it are described on the following page:
http://cseweb.ucsd.edu/classes/wi14/cse260-a/Dirac.html
Though Dirac supports interactive use, its interactive resources are a scarce commodity. So, we've provided you with interactive GPU resources for code development. These resources are described in the following document
http://cseweb.ucsd.edu/classes/wi14/cse260-a/gpuStations.html
Running batch jobs on Dirac is similar how you run on Bang: with the qsub command. There is no qlogin command, but there are interactive queues accessible via qsub. This is explained in the CUDA documentation. Use Dirac's front end, Carver, to edit and compile.
It is not possible to run GPU jobs on the front end; if you attempt to do so, you'll get an error message similar to this one here:
Cuda error: Get Count: CUDA driver version is insufficient for CUDA runtime version.
The code enables you to repeatedly execute matrix multiplication via the -r flag. Adjust the repetition count to limit the running times to about 5 seconds (a value of 50 will probably be sufficient).
Use the dedicated batch queues on Dirac to collect timings. Use the interactive queues (when available) to tune your code's performance. You may also use the cseclass machines, but beware that only cseclass01 and 02 have the same SM organization as Dirac. The SMs on the remaining machines (03 through 07) have 48 core SMs, so the optimal code and thread geometry may differ.
The provided code includes the sequence of calls needed to take timings. Take at least 3 timings for each combination of n and block size, By default, the code will use the same timer as in the previous assignment, which is based on gettimeofday(). Note that, as discussed in class, it is important to invoke cudaThreadSynchronize() to correctly time the kernel launch. and report the minimum timing.
Timings on a dedicated Dirac GPU (i.e. batch) should be highly reproducible, since you have sole access to the device when running on it. This is not possible on interactive resources, as timings on the host will feel contention from other users and can vary much more. As a result, the time to transfer data between host and device, and time to run code on the host can vary a lot more than the time to run a kernel on the device. If you are working on a desktop or a laptop, shut down all open applications.
Do not run on a machine shared with other users, unless you are sure that no-one else is running at the time you conduct your runs. If the timings are inconsistent across runs, other activities are occupying the processor and must be stopped. There may also be interference from system activities. It is possible to take timings on the device only. This will ensure that inconsistent host/device transfer times won't taint your results. On a non-dedicated resource, it may be helpful to use the CUDA timer. This timer is enabled by adding the following line to your Makefile
NVCCFLAGS += -DCUDA_TIMER
GPU timers are discussed in CUDA C Best Practices Guide, §8.1.2.
When reporting performance results, it is important to identify the front end as well as the GPU device and to report device characteristics. However, you only need to report this information if using platforms other than Dirac (i.e CSEClassXX, or your own machine). You can determine important information about the device via information reported by the provided code:
1 Devices Device 0 has 14 cores Device # 0 has 2.624451 GB global memory Device is a Tesla C2050, capability: 2.0 CUDA Driver version: 6000, runtime version: 5050
CUDA provides profiling tools, which are discussed at http://docs.nvidia.com/cuda/profiler-users-guide. You have a choice of command line vs visual interface.
If using the visual interface, be sure to follow these instructions for how to handle remote dislay in ssh. The visual profiler may not be so useful on Dirac, due to the delays in getting on the interactive queue.
The command line tool is called: nvprof, and may be run within a batch job. Look a the command line section of the documentation at http://docs.nvidia.com/cuda/profiler-users-guide/#compute-command-line-profiler-overview
To use the profiler take the following steps.
export COMPUTE_PROFILE=1 export COMPUTE_PROFILE_LOG=~/nvprof.txt export COMPUTE_PROFILE_CONFIG=~/nvprof_config.txt
gpustarttimestamp gridsize3d threadblocksize active_warps active_cycles
make clean; make debug=1 ./mmpy -n 1024 -x 32 -y 32 -r 1 -R
We will add questions to this section as the need arises.
Scott B. Baden Fri [Wed Jan 22 18:19:02 PST 2014]