DeviceTuning

Choosing the launch settings of GPU::transform() for a query: the block size, and in a CUDA build the threads the compiler is asked to keep resident on each multiprocessor, which fixes how many registers a thread may use (see Launch settings). It is the counterpart, on a GPU, of HostTuning. Every pair of settings is a kernel of its own, compiled in advance, so the example compiles a few candidates, times each on a sample of the real queries and runs the rest with the fastest: what an application that launches one query many times can do once at startup.

The example is meant for a GPU build; a plain C++ build runs GPU::transform() as a host loop, has nothing to tune, and says so. It has no host section and opens no window. The source is at Examples/DeviceTuning/main.cpp, in the following sections.

The query

The signed distance to a mesh (the armadillo by default) with a ball cut out of it, through a Tape: the kind of query whose kernel uses many registers, and whose speed depends on how many it gets.

The candidates

GPU::transform<BlockSize, MinResidentThreads>() is a different kernel for every pair, so the candidates are a table of launch functions, one per pair, each a line of its own:

template <unsigned int BlockSize, unsigned int MinResidentThreads>
void launch(const Distance& a_query, const In a_in, const Out a_out)
{
  EBGeometry::GPU::transform<BlockSize, MinResidentThreads>(a_query, a_in, a_out);
}

The table holds block sizes 64, 128 and 256, each with no minimum of resident threads (the compiler picks the register budget), 384 (the default, at most 168 registers a thread) and 768 (at most 80).

On the device

The tape’s pool is mirrored to the device once, and the million points and their results go into a pool of their own, mirrored the same way, so that a launch over spans of that copy allocates and copies nothing and its time is the kernel’s. Each candidate is timed on the first 100,000 points (the fastest of three launches, after one to warm up) and printed beside the defaults’ time divided by its own, so that above 1 is faster than the defaults; the other 900,000 then run with the fastest. The best setting depends on the device, the query and the precision, which is why the example measures rather than prescribes.

Building and running

Build it for a GPU (see Building for the three ways to compile it, and Running on a GPU), in single precision, since many GPUs are much slower in double:

cd Examples/DeviceTuning
make GPU=CUDA PRECISION=float
./DeviceTuning.ex