3#include <AMReX_Config.H>
9#if defined(AMREX_USE_CUDA)
15# include <mkl_version.h>
16# include <oneapi/mkl/spblas.hpp>
40template <
typename T,
typename Index = Long>
43 using CI = std::conditional_t<std::is_const_v<T>, Index
const, Index>;
58template <
typename T,
template <
typename>
class V,
typename Index =
Long>
81 mat.resize(num_non_zeros);
119template <
typename C,
typename T,
template<
typename>
class AD,
template<
typename>
class AS,
121requires (std::same_as<C,Gpu::HostToDevice> ||
122 std::same_as<C,Gpu::DeviceToHost> ||
123 std::same_as<C,Gpu::DeviceToDevice>)
133 dst.
mat.resize(src.
mat.size());
151template <
typename T,
template <
typename>
class V,
typename Index>
154 if (
nnz <= 0) {
return; }
161#if defined(AMREX_USE_CUDA) || defined(AMREX_USE_HIP)
163 constexpr int nthreads = 256;
169 int nblocks = (nr + nwarps_per_block-1) / nwarps_per_block;
180 auto* pmat =
mat.data();
188 constexpr int SHORT_ROW = std::clamp(
int(256/(
sizeof(Index)+
sizeof(T))), 4, 16);
191 Long const b = prow[r];
192 int const len =
int(prow[r+1] - b);
193 if (len <= 1 || len > SHORT_ROW) {
return; }
194 Index keys[SHORT_ROW];
196 for (
int i = 0; i < len; ++i) {
198 if (i > 0) { sorted = sorted && (keys[i-1] <= keys[i]); }
200 if (sorted) {
return; }
202 for (
int i = 0; i < len; ++i) {
205 for (
int i = 1; i < len; ++i) {
206 Index
const k = keys[i];
209 while (j >= 0 && keys[j] > k) {
217 for (
int i = 0; i < len; ++i) {
223#if defined(AMREX_USE_CUDA) || defined(AMREX_USE_HIP)
226 auto* d_needs_fallback = needs_fallback.
data();
232 int r =
int(blockIdx.x)*nwarps_per_block + wid;
235 Long const b = prow[r];
236 Long const e = prow[r+1];
237 auto const len =
int(e - b);
239 if (len <= 1)
return;
245 sorted = sorted && (pcol[b+i-1] <= pcol[b+i]);
247#if defined(AMREX_USE_CUDA)
248 if (__all_sync(0xffffffff, sorted)) {
return; }
250 if (__all(sorted)) {
return; }
256 if (len <= ITEMS_PER_WARP)
258#if defined(AMREX_USE_CUDA)
259 using WarpSort = cub::WarpMergeSort<Index, ITEMS_PER_THREAD, Gpu::Device::warp_size, T>;
260 __shared__
typename WarpSort::TempStorage temp_storage[nwarps_per_block];
261#elif defined(AMREX_USE_HIP)
262 using WarpSort = rocprim::warp_sort<Index, Gpu::Device::warp_size, T>;
263 __shared__
typename WarpSort::storage_type temp_storage[nwarps_per_block];
266 Index keys[ITEMS_PER_THREAD];
267 T values[ITEMS_PER_THREAD];
270 for (
int i = 0; i < ITEMS_PER_THREAD; ++i) {
271 int idx = lane * ITEMS_PER_THREAD + i;
273 keys[i] = pcol[b + idx];
274 values[i] = pmat[b + idx];
276 keys[i] = std::numeric_limits<Index>::max();
282 WarpSort{}.sort(keys, values, temp_storage[wid]),
283 WarpSort(temp_storage[wid]).Sort(
284 keys, values, [](Index
x, Index
y) {
return x <
y;}));
287 for (
int i = 0; i < ITEMS_PER_THREAD; ++i) {
288 int idx = lane * ITEMS_PER_THREAD + i;
290 pcol[b + idx] = keys[i];
291 pmat[b + idx] = values[i];
301 auto* h_needs_fallback = needs_fallback.copyToHost();
303 if (*h_needs_fallback)
308 V<Index> col_index_out(
col_index.size());
309 V<T> mat_out(
mat.size());
310 auto* d_col_out = col_index_out.data();
311 auto* d_val_out = mat_out.data();
313 std::size_t temp_bytes = 0;
316 rocprim::segmented_radix_sort_pairs,
317 cub::DeviceSegmentedRadixSort::SortPairs)
318 (
nullptr, temp_bytes, pcol, d_col_out, pmat, d_val_out,
319 nnz, nr, prow, prow+1, 0,
int(
sizeof(Index)*CHAR_BIT),
325 rocprim::segmented_radix_sort_pairs,
326 cub::DeviceSegmentedRadixSort::SortPairs)
327 (d_temp, temp_bytes, pcol, d_col_out, pmat, d_val_out,
328 nnz, nr, prow, prow+1, 0,
int(
sizeof(Index)*CHAR_BIT),
332 std::swap(
mat, mat_out);
342#elif defined(AMREX_USE_SYCL)
345 auto* d_needs_fallback = needs_fallback.
data();
349 Long const b = prow[r];
350 Long const e = prow[r+1];
351 if (e - b <= SHORT_ROW) {
return; }
352 for (
Long i = b+1; i < e; ++i) {
353 if (pcol[i-1] > pcol[i]) {
360 auto* h_needs_fallback = needs_fallback.copyToHost();
362 if (*h_needs_fallback)
366 auto& q = Gpu::Device::streamQueue();
367 oneapi::mkl::sparse::matrix_handle_t handle{};
368 oneapi::mkl::sparse::init_matrix_handle(&handle);
369#if defined(INTEL_MKL_VERSION) && (INTEL_MKL_VERSION < 20250300)
370 oneapi::mkl::sparse::set_csr_data(q, handle, Index(nr), Index(ncols),
371 oneapi::mkl::index_base::zero, prow, pcol, pmat);
373 oneapi::mkl::sparse::set_csr_data(q, handle, Index(nr), Index(ncols), Index(
nnz),
374 oneapi::mkl::index_base::zero, prow, pcol, pmat);
376 oneapi::mkl::sparse::sort_matrix(q, handle, {}).wait();
377 oneapi::mkl::sparse::release_matrix_handle(q, &handle).wait();
391template <
typename T,
template <
typename>
class V,
typename Index>
394 if (
nnz <= 0) {
return; }
396 constexpr int SMALL = 128;
414 for (
Long r = 0; r < nr; ++r) {
417 auto const len =
int(e - b);
419 if (len <= 1) {
continue; }
422 for (
int i = 1; i < len; ++i) {
428 if (sorted) {
continue; }
432 for (
int i = 0; i < len; ++i) {
434 svals[i] =
mat [b+i];
436 for (
int i = 1; i < len; ++i) {
440 while (j > 0 && scols[j-1] > c) {
441 scols[j] = scols[j-1];
442 svals[j] = svals[j-1];
448 for (
int i = 0; i < len; ++i) {
450 mat [b+i] = svals[i];
457 for (
int i = 0; i < len; ++i) {
459 lvals[i] =
mat [b+i];
463 std::ranges::sort(perm,
464 [&] (
int i0,
int i1) {
465 return lcols[i0] < lcols[i1];
468 for (
int out = 0; out < len; ++out) {
469 auto const in = perm[out];
471 mat [b+out] = lvals[in];
480template <
typename Index,
template <
typename>
class V>
486 template <
typename T,
typename J>
490 csr.
nrows <
Long(std::numeric_limits<Index>::max()));
496 auto lnnz =
static_cast<Index
>(
col_index.size());
497 auto lnro =
static_cast<Index
>(
row_offset.size());
504 if (i < lnnz) { col_dst[i] =
static_cast<Index
>(col_src[i]); }
505 if (i < lnro) { row_dst[i] =
static_cast<Index
>(row_src[i]); }
509 template <
typename T,
typename J>
512 static_assert(!std::is_const_v<T>);
514 auto lnnz =
static_cast<Index
>(
col_index.size());
515 auto lnro =
static_cast<Index
>(
row_offset.size());
522 if (i < lnnz) { col_dst[i] =
static_cast<J
>(col_src[i]); }
523 if (i < lnro) { row_dst[i] =
static_cast<J
>(row_src[i]); }
527 template <
typename T,
template <
typename>
class U,
typename J>
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_RESTRICT
Definition AMReX_Extension.H:37
#define AMREX_HIP_OR_CUDA(a, b)
Definition AMReX_GpuControl.H:17
#define AMREX_GPU_SAFE_CALL(call)
Definition AMReX_GpuError.H:63
#define AMREX_GPU_ERROR_CHECK()
Definition AMReX_GpuError.H:151
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Convenience header for the core AMReX GPU facilities.
virtual void free(void *pt)=0
Free a previously allocated block pointed to by pt.
virtual void * alloc(std::size_t sz)=0
Allocate sz bytes from this arena.
Definition AMReX_GpuBuffer.H:24
T const * data() const noexcept
Definition AMReX_GpuBuffer.H:51
static constexpr int warp_size
Definition AMReX_GpuDevice.H:239
amrex_long Long
Definition AMReX_INT.H:30
T Max(N n, T const *v, T init_val=std::numeric_limits< T >::lowest())
Compute the maximum of an array of values.
Definition AMReX_Reduce.H:1125
Arena * The_Arena()
Definition AMReX_Arena.cpp:839
__host__ __device__ AMREX_FORCE_INLINE void AddNoRet(T *sum, T value) noexcept
Definition AMReX_GpuAtomic.H:283
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
A host-to-device copy routine. Note this is just a wrapper around memcpy, so it assumes contiguous st...
Definition AMReX_GpuContainers.H:228
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:329
gpuStream_t gpuStream() noexcept
Definition AMReX_GpuDevice.H:310
Definition AMReX_Amr.cpp:50
@ C
Definition AMReX_Order.H:7
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
@ y
Definition AMReX_Orientation.H:14
@ x
Definition AMReX_Orientation.H:14
void duplicateCSR(C c, CSR< T, AD, Index > &dst, CSR< T, AS, Index > const &src)
Definition AMReX_CSR.H:131
const int[]
Definition AMReX_BLProfiler.cpp:1665
__global__ void launch_global(L f0, Lambdas... fs)
Definition AMReX_GpuLaunch.H:68
Owning CSR container backed by AMReX resizable vectors.
Definition AMReX_CSR.H:59
CsrView< T, Index > view()
Mutable view of the underlying buffers.
Definition AMReX_CSR.H:88
V< Index > col_index
Definition AMReX_CSR.H:62
void resize(Long num_rows, Long num_non_zeros)
Resize the storage to accommodate num_rows and num_non_zeros entries.
Definition AMReX_CSR.H:80
Index index_type
Definition AMReX_CSR.H:60
V< T > mat
Definition AMReX_CSR.H:61
V< Index > row_offset
Definition AMReX_CSR.H:63
CsrView< T const, Index > view() const
Const view of the underlying buffers.
Definition AMReX_CSR.H:94
Long nrows() const
Number of logical rows represented by the CSR offset array.
Definition AMReX_CSR.H:67
void sort()
Sort each row by column index. Uses GPU acceleration when possible.
Definition AMReX_CSR.H:152
void sort_on_host()
Host-only fallback that sorts column indices row by row.
Definition AMReX_CSR.H:392
Long nnz
Definition AMReX_CSR.H:64
CsrView< T const, Index > const_view() const
Convenience alias for view() const.
Definition AMReX_CSR.H:103
Definition AMReX_CSR.H:482
V< Index > row_offset
Definition AMReX_CSR.H:484
void copyFrom(CsrView< T, J > const &csr)
Definition AMReX_CSR.H:487
void copyTo(CSR< T, U, J > &csr) const
Definition AMReX_CSR.H:528
void copyTo(CsrView< T, J > const &csr) const
Definition AMReX_CSR.H:510
V< Index > col_index
Definition AMReX_CSR.H:483
Lightweight non-owning CSR view that can point to host or device buffers.
Definition AMReX_CSR.H:41
Index index_type
Definition AMReX_CSR.H:42
Long nrows
Definition AMReX_CSR.H:48
Long nnz
Definition AMReX_CSR.H:47
CI *__restrict__ col_index
Definition AMReX_CSR.H:45
T *__restrict__ mat
Definition AMReX_CSR.H:44
CI *__restrict__ row_offset
Definition AMReX_CSR.H:46
std::conditional_t< std::is_const_v< T >, Index const, Index > CI
Definition AMReX_CSR.H:43