18#if defined(MFEM_USE_CUDA_OR_HIP) && !defined(MFEM_USE_CUDA_OR_HIP_LANG)
19#error "This header requires compilation with CUDA/HIP language!"
23#include <cub/device/device_scan.cuh>
24#include <cub/device/device_select.cuh>
25#define MFEM_CUB_NAMESPACE cub
26#elif defined(MFEM_USE_HIP)
27#include <hipcub/device/device_scan.hpp>
28#include <hipcub/device/device_select.hpp>
29#define MFEM_CUB_NAMESPACE hipcub
41template <
class InputIt,
class OutputIt>
42void InclusiveScan(
bool use_dev, InputIt d_in, OutputIt d_out,
size_t num_items)
45#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
49 size_t bytes = workspace.
Size();
52 auto error = MFEM_CUB_NAMESPACE::DeviceScan::InclusiveSum(
53 workspace.
Write(), bytes, d_in, d_out, num_items);
54#if defined(MFEM_USE_CUDA)
55 if (error == cudaSuccess)
59#elif defined(MFEM_USE_HIP)
60 if (error == hipSuccess)
68 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceScan::InclusiveSum(
69 nullptr, bytes, d_in, d_out, num_items));
71 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceScan::InclusiveSum(
72 workspace.
Write(), bytes, d_in, d_out, num_items));
77 std::inclusive_scan(d_in, d_in + num_items, d_out);
86 for (
size_t i = 1; i < num_items; ++i)
88 *d_out = (*prev) + (*d_in);
105template <
class InputIt,
class OutputIt,
class ScanOp>
106void InclusiveScan(
bool use_dev, InputIt d_in, OutputIt d_out,
size_t num_items,
109#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
113 size_t bytes = workspace.
Size();
116 auto error = MFEM_CUB_NAMESPACE::DeviceScan::InclusiveScan(
117 workspace.
Write(), bytes, d_in, d_out, scan_op, num_items);
118#if defined(MFEM_USE_CUDA)
119 if (error == cudaSuccess)
123#elif defined(MFEM_USE_HIP)
124 if (error == hipSuccess)
132 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceScan::InclusiveScan(
133 nullptr, bytes, d_in, d_out, scan_op, num_items));
135 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceScan::InclusiveScan(
136 workspace.
Write(), bytes, d_in, d_out, scan_op, num_items));
141 std::inclusive_scan(d_in, d_in + num_items, d_out, scan_op);
150 for (
size_t i = 1; i < num_items; ++i)
152 *d_out = scan_op(*prev, *d_in);
168template <
class InputIt,
class OutputIt,
class T,
class ScanOp>
169void ExclusiveScan(
bool use_dev, InputIt d_in, OutputIt d_out,
size_t num_items,
170 T init_value, ScanOp scan_op)
172#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
176 size_t bytes = workspace.
Size();
179 auto error = MFEM_CUB_NAMESPACE::DeviceScan::ExclusiveScan(
180 workspace.
Write(), bytes, d_in, d_out, scan_op, init_value,
182#if defined(MFEM_USE_CUDA)
183 if (error == cudaSuccess)
187#elif defined(MFEM_USE_HIP)
188 if (error == hipSuccess)
196 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceScan::ExclusiveScan(
197 nullptr, bytes, d_in, d_out, scan_op, init_value, num_items));
199 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceScan::ExclusiveScan(
200 workspace.
Write(), bytes, d_in, d_out, scan_op, init_value,
206 std::exclusive_scan(d_in, d_in + num_items, d_out, init_value, scan_op);
211 for (
size_t i = 0; i < num_items; ++i)
213 auto next = scan_op(init_value, *d_in);
225template <
class InputIt,
class OutputIt,
class T>
226void ExclusiveScan(
bool use_dev, InputIt d_in, OutputIt d_out,
size_t num_items,
229 ExclusiveScan(use_dev, d_in, d_out, num_items, init_value, std::plus<> {});
241template <
class InputIt,
class FlagIt,
class OutputIt,
class NumSelectedIt>
242void CopyFlagged(
bool use_dev, InputIt d_in, FlagIt d_flags, OutputIt d_out,
243 NumSelectedIt d_num_selected_out,
size_t num_items)
245#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
250 size_t bytes = workspace.
Size();
253 auto error = MFEM_CUB_NAMESPACE::DeviceSelect::Flagged(
254 workspace.
Write(), bytes, d_in, d_flags, d_out, d_num_selected_out,
256#if defined(MFEM_USE_CUDA)
257 if (error == cudaSuccess)
261#elif defined(MFEM_USE_HIP)
262 if (error == hipSuccess)
270 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceSelect::Flagged(
271 nullptr, bytes, d_in, d_flags, d_out, d_num_selected_out, num_items));
273 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceSelect::Flagged(
274 workspace.
Write(), bytes, d_in, d_flags, d_out, d_num_selected_out,
279 *d_num_selected_out = 0;
280 for (
size_t i = 0; i < num_items; ++i, ++d_in, ++d_flags)
286 ++*d_num_selected_out;
298template <
class InputIt,
class OutputIt,
class NumSelectedIt,
class SelectOp>
299void CopyIf(
bool use_dev, InputIt d_in, OutputIt d_out,
300 NumSelectedIt d_num_selected_out,
size_t num_items,
303#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
307#if defined(MFEM_USE_CUDA) && \
308 (__CUDACC_VER_MAJOR__ < 12 || \
309 (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ < 5))
312 auto ptr = flags.
Write();
314 [=] MFEM_HOST_DEVICE(
int i) { ptr[i] = select_op(d_in[i]); });
315 CopyFlagged(use_dev, d_in, ptr, d_out, d_num_selected_out, num_items);
318 size_t bytes = workspace.
Size();
321 auto error = MFEM_CUB_NAMESPACE::DeviceSelect::If(
322 workspace.
Write(), bytes, d_in, d_out, d_num_selected_out,
323 num_items, select_op);
324#if defined(MFEM_USE_CUDA)
325 if (error == cudaSuccess)
329#elif defined(MFEM_USE_HIP)
330 if (error == hipSuccess)
338 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceSelect::If(
339 nullptr, bytes, d_in, d_out, d_num_selected_out, num_items,
342 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceSelect::If(
343 workspace.
Write(), bytes, d_in, d_out, d_num_selected_out, num_items,
349 *d_num_selected_out = 0;
350 for (
size_t i = 0; i < num_items; ++i, ++d_in)
352 if (select_op(*d_in))
356 ++*d_num_selected_out;
368template <
class InputIt,
class OutputIt,
class NumSelectedIt>
370 NumSelectedIt d_num_selected_out,
size_t num_items)
372#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
377 size_t bytes = workspace.
Size();
380 auto error = MFEM_CUB_NAMESPACE::DeviceSelect::Unique(
381 workspace.
Write(), bytes, d_in, d_out, d_num_selected_out,
383#if defined(MFEM_USE_CUDA)
384 if (error == cudaSuccess)
388#elif defined(MFEM_USE_HIP)
389 if (error == hipSuccess)
397 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceSelect::Unique(
398 nullptr, bytes, d_in, d_out, d_num_selected_out, num_items));
400 MFEM_GPU_CHECK(MFEM_CUB_NAMESPACE::DeviceSelect::Unique(
401 workspace.
Write(), bytes, d_in, d_out, d_num_selected_out,
406 *d_num_selected_out =
407 std::unique_copy(d_in, d_in + num_items, d_out) - d_out;
411#undef MFEM_CUB_NAMESPACE
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
T * Write(bool on_dev=true)
Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
void ExclusiveScan(bool use_dev, InputIt d_in, OutputIt d_out, size_t num_items, T init_value, ScanOp scan_op)
void CopyFlagged(bool use_dev, InputIt d_in, FlagIt d_flags, OutputIt d_out, NumSelectedIt d_num_selected_out, size_t num_items)
Equivalent to *d_num_selected_out = std::copy_if(d_in, d_in+num_items, d_out, [=](auto iter){ return ...
void CopyUnique(bool use_dev, InputIt d_in, OutputIt d_out, NumSelectedIt d_num_selected_out, size_t num_items)
equivalent to *d_num_selected_out = std::unique_copy(d_in, d_in+num_items, d_out) - d_out;
void InclusiveScan(bool use_dev, InputIt d_in, OutputIt d_out, size_t num_items)
void CopyIf(bool use_dev, InputIt d_in, OutputIt d_out, NumSelectedIt d_num_selected_out, size_t num_items, SelectOp select_op)
Equivalent to *d_num_selected_out = std::copy_if(d_in, d_in+num_items, d_out, select_op) - d_out;.
void forall(int N, lambda &&body)
@ HIP_MASK
Biwise-OR of all HIP backends.
@ CUDA_MASK
Biwise-OR of all CUDA backends.