EBGeometry
Compact, header-only C++ library for fast evaluation of signed distance functions
Loading...
Searching...
No Matches
Namespaces | Typedefs | Functions | Variables
EBGeometry_GPUTransform.hpp File Reference

GPU::parallelFor() and GPU::transform(), which run a functor over many indices or inputs: in a kernel in a CUDA or HIP build, and in a host loop otherwise. More...

#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <vector>
#include "EBGeometry_GPU.hpp"
#include "EBGeometry_GPURuntime.hpp"
#include "EBGeometry_MemoryResource.hpp"
#include "EBGeometry_PODVector.hpp"
#include "EBGeometry_GPUTransformImplem.hpp"
Include dependency graph for EBGeometry_GPUTransform.hpp:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Namespaces

namespace  EBGeometry
 Namespace containing all of EBGeometry's functionality.
 
namespace  EBGeometry::GPU
 Backend-neutral GPU runtime API surface (CUDA or HIP).
 

Typedefs

template<class Query , class In >
using EBGeometry::GPU::TransformResult = std::decay_t< std::invoke_result_t< const Query &, const In & > >
 The result type of a query on an input.
 

Functions

bool EBGeometry::GPU::deviceAvailable () noexcept
 Whether a GPU is visible to the runtime.
 
MemoryResource & EBGeometry::GPU::memoryResource () noexcept
 The memory a query's data must live in for parallelFor() and transform() to read it.
 
template<unsigned int BlockSize = DefaultBlockSize, unsigned int MinResidentThreads = DefaultMinResidentThreads, class F >
void EBGeometry::GPU::parallelFor (std::size_t a_n, const F &a_f)
 Run a functor on every index: a_f(i) for i = 0, ..., a_n - 1, in no particular order.
 
template<unsigned int BlockSize = DefaultBlockSize, unsigned int MinResidentThreads = DefaultMinResidentThreads, class Query , class In , class Out >
void EBGeometry::GPU::transform (const Query &a_query, PODSpan< In > a_in, PODSpan< Out > a_out)
 Run a query on every input in place: a_out[i] = a_query(a_in[i]), with no allocation and no copies.
 
template<unsigned int BlockSize = DefaultBlockSize, unsigned int MinResidentThreads = DefaultMinResidentThreads, class Query , class In , class Out >
void EBGeometry::GPU::transform (const Query &a_query, const Pool &a_pool, const PODVector< In > &a_in, const PODVector< Out > &a_out)
 Run a query on every input of a pool-resident array, writing the results into another array in the same pool: out[i] = a_query(in[i]), with no allocation and no copies.
 
template<unsigned int BlockSize = DefaultBlockSize, unsigned int MinResidentThreads = DefaultMinResidentThreads, class Query , class In , class Out >
void EBGeometry::GPU::transform (const Query &a_query, const std::vector< In > &a_in, std::vector< Out > &a_out)
 Run a query on every input, from host memory to host memory: a_out[i] = a_query(a_in[i]).
 

Variables

constexpr bool EBGeometry::GPU::enabled = false
 Whether this translation unit is compiled as CUDA or HIP, so that parallelFor() and transform() run a kernel.
 
constexpr const char * EBGeometry::GPU::backendName = "host"
 Where parallelFor() and transform() run in this translation unit: "HIP", "CUDA" or "host".
 
constexpr unsigned int EBGeometry::GPU::DefaultBlockSize = 128
 The number of threads per block a launch uses unless it is given another.
 
constexpr unsigned int EBGeometry::GPU::DefaultMinResidentThreads = 384
 The threads a launch asks the CUDA compiler to keep resident on each multiprocessor, at least, unless it is given another: 384, three blocks of 128, which holds a thread to at most 168 registers.
 

Detailed Description

GPU::parallelFor() and GPU::transform(), which run a functor over many indices or inputs: in a kernel in a CUDA or HIP build, and in a host loop otherwise.

GPU::transform() works like std::transform or thrust::transform: it writes a_query(in[i]) to out[i], into an output the caller provides. A query is a trivially copyable functor whose call operator is EBGEOMETRY_HOST_DEVICE and maps one input to one result. It holds what it evaluates by value: an analytic shape, or a pool-resident object rebased onto memory the device can read (a mirror in GPU::memoryResource(), or a frozen managed pool; see the memory model in the user documentation). One source then serves both builds: a CUDA or HIP translation unit launches a kernel, and any other runs the same functor in a host loop, so a plain C++ build needs no GPU toolkit. The GPU:: prefix names where these calls can run, not where they always do. GPU::enabled says which of the two a translation unit gets, and GPU::deviceAvailable() whether a device is visible at run time.

The calls are layered, each built on the one below:

Every launch takes its block size as a template parameter (GPU::DefaultBlockSize unless given), so that the kernel can carry it as launch bounds. Every call is synchronous: it returns once the kernel has finished. Every transform requires as many results as inputs, and results of exactly the query's result type.

Author
Robert Marskar