20#ifndef DEM_SOLVER_FUSED_HPP
21#define DEM_SOLVER_FUSED_HPP
25#include <Kokkos_Core.hpp>
37 Kokkos::View<unsigned*, CpMem>
bar;
64#ifdef KOKKOS_ENABLE_CUDA
65 return mode < 0 ? !graphReplayAvailable : mode == 1;
67 (void)graphReplayAvailable;
73#ifdef KOKKOS_ENABLE_CUDA
85__device__
inline void demGridBarrier(
unsigned* count,
unsigned k) {
87 if (threadIdx.x == 0) {
90 const unsigned target = (k + 1u) * gridDim.x;
91 while (*
reinterpret_cast<volatile unsigned*
>(count) < target) {
100inline constexpr int kFusedBarWords = 32769;
106template <
class Sweep>
107__global__
void demFusedColorSweepK(Sweep f, Kokkos::View<const int*, CpMem> perm,
108 Kokkos::View<const int*, CpMem> offs,
int numColors,
110 const int stride = gridDim.x * blockDim.x;
111 const int tid = blockIdx.x * blockDim.x + threadIdx.x;
113 for (
int c = 0; c < numColors; ++c) {
114 const int b = offs(c), e = offs(c + 1);
117 for (
int i = b + tid; i < e; i += stride)
119 if (c + 1 < numColors)
120 demGridBarrier(bar, k++);
129template <
class Sweep>
130__global__
void demFusedSweepLoopK(Sweep f, Kokkos::View<const int*, CpMem> perm,
131 Kokkos::View<const int*, CpMem> offs,
int numColors,
132 int maxIters,
float tol,
bool strictLess,
float* res,
133 unsigned* bar,
int* iters) {
134 const int stride = gridDim.x * blockDim.x;
135 const int tid = blockIdx.x * blockDim.x + threadIdx.x;
138 for (
int it = 0; it < maxIters; ++it) {
142 demGridBarrier(bar, k++);
143 for (
int c = 0; c < numColors; ++c) {
144 const int b = offs(c), e = offs(c + 1);
147 for (
int i = b + tid; i < e; i += stride)
149 demGridBarrier(bar, k++);
151 const float r = *
reinterpret_cast<volatile float*
>(res);
152 if (strictLess ? (r < tol) : (r <= tol))
154 demGridBarrier(bar, k++);
156 if (iters !=
nullptr && tid == 0)
160inline constexpr int kFusedBlock = 256;
165template <
class Kernel>
166inline int demFusedMaxGrid(Kernel kernel) {
167 static const int maxGrid = [kernel] {
169 if (cudaOccupancyMaxActiveBlocksPerMultiprocessor(&perSm, kernel, kFusedBlock, 0) !=
171 (void)cudaGetLastError();
175 if (cudaGetDevice(&dev) != cudaSuccess ||
176 cudaDeviceGetAttribute(&sm, cudaDevAttrMultiProcessorCount, dev) != cudaSuccess) {
177 (void)cudaGetLastError();
188template <
class Sweep>
189inline bool demLaunchFusedColorSweep(
CpExec& space,
const Sweep& f,
190 Kokkos::View<const int*, CpMem> perm,
const FusedSweepCtx& ctx,
192 const int maxGrid = std::min(demFusedMaxGrid(demFusedColorSweepK<Sweep>),
193 (
static_cast<int>(ctx.bar.extent(0)) - 1) / 8);
194 if (maxGrid <= 0 || numColors <= 0 || ctx.maxBucket <= 0)
196 const int want = (ctx.maxBucket + kFusedBlock - 1) / kFusedBlock;
197 const int grid = want < maxGrid ? want : maxGrid;
198 cudaStream_t str = space.cuda_stream();
199 cudaMemsetAsync(ctx.bar.data(), 0, (
static_cast<std::size_t
>(grid) * 8 + 1) *
sizeof(
unsigned),
201 demFusedColorSweepK<Sweep>
202 <<<grid, kFusedBlock, 0, str>>>(f, perm, ctx.offsDev, numColors, ctx.bar.data());
209template <
class Sweep>
210inline bool demLaunchFusedSweepLoop(
CpExec& space,
const Sweep& f,
211 Kokkos::View<const int*, CpMem> perm,
const FusedSweepCtx& ctx,
212 int numColors,
const FusedLoopSpec& spec,
float* res) {
213 const int maxGrid = std::min(demFusedMaxGrid(demFusedSweepLoopK<Sweep>),
214 (
static_cast<int>(ctx.bar.extent(0)) - 1) / 8);
215 if (maxGrid <= 0 || numColors <= 0 || ctx.maxBucket <= 0 || res ==
nullptr)
217 const int want = (ctx.maxBucket + kFusedBlock - 1) / kFusedBlock;
218 const int grid = want < maxGrid ? want : maxGrid;
219 cudaStream_t str = space.cuda_stream();
220 cudaMemsetAsync(ctx.bar.data(), 0, (
static_cast<std::size_t
>(grid) * 8 + 1) *
sizeof(
unsigned),
222 demFusedSweepLoopK<Sweep><<<grid, kFusedBlock, 0, str>>>(f, perm, ctx.offsDev, numColors,
223 spec.maxIters, spec.tol, spec.strictLess,
224 res, ctx.bar.data(), spec.iters);
234 Kokkos::View<int*, CpMem> offsDev,
235 Kokkos::View<unsigned*, CpMem> bar) {
237#ifdef KOKKOS_ENABLE_CUDA
238 if (offs.size() < 2 || offs.size() > offsDev.extent(0) +
static_cast<std::size_t
>(0))
241 for (std::size_t c = 0; c + 1 < offs.size(); ++c)
242 maxBucket = std::max(maxBucket, offs[c + 1] - offs[c]);
245 const Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged> h(offs.data(),
247 auto d = Kokkos::subview(offsDev, Kokkos::pair<std::size_t, std::size_t>(0, offs.size()));
248 Kokkos::deep_copy(space, d, h);
249 ctx.
offsDev = Kokkos::subview(Kokkos::View<const int*, CpMem>(offsDev),
250 Kokkos::pair<std::size_t, std::size_t>(0, offs.size()));
bool demFusedWanted(bool graphReplayAvailable, int mode)
Fused-sweep policy.
FusedSweepCtx demMakeFusedCtx(CpExec &space, const std::vector< int > &offs, Kokkos::View< int *, CpMem > offsDev, Kokkos::View< unsigned *, CpMem > bar)
Fill a FusedSweepCtx from buildColorBucketsKokkos's host offsets: async-upload them into the pooled d...
Kokkos::DefaultExecutionSpace CpExec
Device-side iteration loop: run up to maxIters sweeps of the colour classes inside ONE kernel,...
Device-side context for a fused colour sweep: the colour offsets (numColors+1, uploaded from buildCol...
Kokkos::View< const int *, CpMem > offsDev
Kokkos::View< unsigned *, CpMem > bar