C/C++

Debugging 256 GPU Threads in Visual Studio 2013

With Microsoft C++ AMP and Visual Studio, you can easily debug hundreds of GPU threads.

In the previous article in this two-part series on Microsoft C++ AMP with Visual Studio 2013, I explained usage details for CPU and GPU debugging capabilities in Visual Studio 2013. In this article, I explore more-advanced debugging features, focusing on complex GPU code that uses tiling optimizations.

Debugging C++ AMP Code with Tiling Optimizations

Tiling is a common optimization technique when coding GPU kernels (that is, functions sent from the CPU for execution on the GPU). In fact, if you have experience with OpenCL or CUDA, you will be accustomed to working with tiling optimization. C++ AMP also allows you to explicitly tile the computation to take advantage of the GPU memory hierarchy with the tile_static storage class to access tile_static memory. Thus, you can partition data into smaller subsets as you would in optimized kernels with either OpenCL or CUDA.

Correct use of tiling optimization in appropriate algorithms can boost performance compared with baseline execution without tiling. However, as happens with any optimization technique, the code is usually more difficult to understand and there are new challenges to be met when debugging the optimized code. Fortunately, the C++ AMP GPU debugging features included in Visual Studio 2013 make it easier for you to understand code with tiling optimization and its execution steps.

The following lines show an example of a C++ AMP application that performs a matrix multiplication with a 256-tile size (16x16). Thus, the code reuses some pieces of data 256 times from very fast memory instead of going to search for these data pieces in the slower global memory. The code is a different version of the typical tiled matrix multiplication Daniel Moth uses as an example in his Microsoft presentations. I've added detailed comments to the code in order to make it easier to understand each block.

The number of GPU threads that the kernel is going to launch makes it challenging for a debugging session. Here, I'm focusing on GPU code, so you have to make sure that your project has the necessary configuration changes (explained in Part 1 of this series) to debug GPU code. If you establish a breakpoint at the line "sum += tile_static_a[row][j] * tile_static_b[j][col]" in the amp_matrix_tiled function, then execute the application until the debugger reaches this breakpoint, you will be able to see the 256 launched GPU threads.

Select Debug | Windows | GPU Threads to activate the GPU Threads window (see Figure 1). Remember that the GPU software emulator allows you to work with four threads, so you will see "4 threads" in the Thread Count column for the amp_matrix_tiled::I7<lambda>Location, and other 252 threads in the same location but in another row (252 + 4 = 256). The GPU Threads window will display the total number of threads: 256.

Select Debug | Windows | Parallel Watch | Parallel Watch 1 and you will see the list of the 256 GPU threads with their Tile and Thread indexes. The Thread coordinates will go from [0, 0] to [15, 15]. Notice that the Tile coordinates are always [0, 0], which means that the 256 threads have been launched for the first tile.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!