31#ifndef __TASMANIAN_SPARSE_GRID_ACCELERATED_DATA_STRUCTURES_HPP
32#define __TASMANIAN_SPARSE_GRID_ACCELERATED_DATA_STRUCTURES_HPP
34#include "tsgAcceleratedHandles.hpp"
81struct AccelerationContext;
98 GpuVector(GpuVector<T>
const &) =
delete;
100 GpuVector<T>& operator =(GpuVector<T>
const &) =
delete;
103 GpuVector(GpuVector<T> &&other) : num_entries(Utils::exchange(other.num_entries, 0)), gpu_data(Utils::exchange(other.gpu_data, nullptr))
104 #ifdef Tasmanian_ENABLE_DPCPP
105 , sycl_queue(other.sycl_queue)
109 GpuVector<T>& operator =(GpuVector<T> &&other){
110 GpuVector<T> temp(std::move(other));
111 std::swap(num_entries, temp.num_entries);
112 std::swap(gpu_data, temp.gpu_data);
113 #ifdef Tasmanian_ENABLE_DPCPP
114 std::swap(sycl_queue, temp.sycl_queue);
120 GpuVector() : num_entries(0), gpu_data(nullptr){}
122 GpuVector(AccelerationContext
const *acc,
size_t count) : num_entries(0), gpu_data(nullptr){ resize(acc, count); }
132 GpuVector(AccelerationContext
const *acc,
int dim1,
int dim2) : num_entries(0), gpu_data(nullptr){ resize(acc, Utils::size_mult(dim1, dim2)); }
134 GpuVector(AccelerationContext
const *acc,
const std::vector<T> &cpu_data) : num_entries(0), gpu_data(nullptr){ load(acc, cpu_data); }
136 GpuVector(AccelerationContext
const *acc,
int dim1,
int dim2, T
const *cpu_data) : num_entries(0), gpu_data(nullptr){ load(acc, Utils::size_mult(dim1, dim2), cpu_data); }
138 template<
typename IteratorLike> GpuVector(AccelerationContext
const *acc, IteratorLike ibegin, IteratorLike iend) : GpuVector(){ load(acc, ibegin, iend); }
140 ~GpuVector(){ clear(); }
143 size_t size()
const{
return num_entries; }
145 T* data(){
return gpu_data; }
147 const T* data()
const{
return gpu_data; }
150 void resize(AccelerationContext
const *acc,
size_t count);
154 bool empty()
const{
return (num_entries == 0); }
157 void load(AccelerationContext
const *acc,
const std::vector<T> &cpu_data){ load(acc, cpu_data.size(), cpu_data.data()); }
160 template<
typename IteratorLike>
161 void load(AccelerationContext
const *acc, IteratorLike ibegin, IteratorLike iend){
162 load(acc, std::distance(ibegin, iend), &*ibegin);
171 Utils::use_if<!std::is_same<U, T>::value> load(AccelerationContext
const *acc,
const std::vector<U> &cpu_data){
172 load(acc, cpu_data.size(), cpu_data.data());
183 void load(AccelerationContext
const *acc,
size_t count,
const T* cpu_data);
190 Utils::use_if<!std::is_same<U, T>::value> load(AccelerationContext
const *acc,
size_t count,
const U* cpu_data){
191 std::vector<T> converted(count);
192 std::transform(cpu_data, cpu_data + count, converted.begin(), [](U
const &x)->T{ return static_cast<T>(x); });
193 load(acc, converted);
196 void unload(AccelerationContext
const *acc, std::vector<T> &cpu_data)
const{
197 cpu_data.resize(num_entries);
198 unload(acc, cpu_data.data());
201 std::vector<T> unload(AccelerationContext
const *acc)
const{
207 void unload(AccelerationContext
const *acc,
size_t num, T* cpu_data)
const;
209 void unload(AccelerationContext
const *acc, T* cpu_data)
const{ unload(acc, num_entries, cpu_data); }
213 T* external = gpu_data;
220 using value_type = T;
225 #ifdef Tasmanian_ENABLE_DPCPP
237 #ifdef Tasmanian_ENABLE_CUDA
239 void setCuBlasHandle(
void *handle);
241 void setCuSparseHandle(
void *handle);
243 void setCuSolverDnHandle(
void *handle);
246 std::unique_ptr<int, HandleDeleter<AccHandle::Cublas>> cublas_handle;
248 std::unique_ptr<int, HandleDeleter<AccHandle::Cusparse>> cusparse_handle;
250 std::unique_ptr<int, HandleDeleter<AccHandle::Cusolver>> cusolver_handle;
253 #ifdef Tasmanian_ENABLE_HIP
255 void setRocBlasHandle(
void *handle);
257 void setRocSparseHandle(
void *handle);
260 std::unique_ptr<int, HandleDeleter<AccHandle::Rocblas>> rblas_handle;
262 std::unique_ptr<int, HandleDeleter<AccHandle::Rocsparse>> rsparse_handle;
265 #ifdef Tasmanian_ENABLE_DPCPP
267 void setSyclQueue(
void *queue);
269 std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>> internal_queue;
273 std::unique_ptr<int> called_magma_init;
284class AccelerationDomainTransform{
287 AccelerationDomainTransform(AccelerationContext
const *, std::vector<double>
const &transform_a, std::vector<double>
const &transform_b);
297 void getCanonicalPoints(
bool use01, T
const gpu_transformed_x[],
int num_x, GpuVector<T> &gpu_canonical_x);
301 GpuVector<double> gpu_trans_a, gpu_trans_b;
302 int num_dimensions, padded_size;
303 AccelerationContext
const *acceleration;
327 void dtrans2can(AccelerationContext
const *acc,
bool use01,
int dims,
int num_x,
int pad_size,
328 const double *gpu_trans_a,
const double *gpu_trans_b,
329 const T *gpu_x_transformed, T *gpu_x_canonical);
344 void devalpwpoly(AccelerationContext
const *acc,
int order,
TypeOneDRule rule,
int num_dimensions,
int num_x,
int num_basis,
const T *gpu_x,
const T *gpu_nodes,
const T *gpu_support, T *gpu_y);
358 void devalpwpoly_sparse(AccelerationContext
const *acc,
int order,
TypeOneDRule rule,
int dims,
int num_x,
const T *gpu_x,
359 const GpuVector<T> &gpu_nodes,
const GpuVector<T> &gpu_support,
360 const GpuVector<int> &gpu_hpntr,
const GpuVector<int> &gpu_hindx,
const GpuVector<int> &gpu_hroots,
361 GpuVector<int> &gpu_spntr, GpuVector<int> &gpu_sindx, GpuVector<T> &gpu_svals);
376 void devalseq(AccelerationContext
const *acc,
int dims,
int num_x,
const std::vector<int> &max_levels,
const T *gpu_x,
377 const GpuVector<int> &num_nodes,
378 const GpuVector<int> &points,
const GpuVector<T> &nodes,
const GpuVector<T> &coeffs, T *gpu_result);
387 void devalfor(AccelerationContext
const *acc,
int dims,
int num_x,
const std::vector<int> &max_levels,
const T *gpu_x,
const GpuVector<int> &num_nodes,
const GpuVector<int> &points, T *gpu_wreal,
typename GpuVector<T>::value_type *gpu_wimag);
398 void devalglo(AccelerationContext
const *acc,
bool is_nested,
bool is_clenshawcurtis0,
int dims,
int num_x,
int num_p,
int num_basis,
399 T
const *gpu_x, GpuVector<T>
const &nodes, GpuVector<T>
const &coeff, GpuVector<T>
const &tensor_weights,
400 GpuVector<int>
const &nodes_per_level, GpuVector<int>
const &offset_per_level, GpuVector<int>
const &map_dimension, GpuVector<int>
const &map_level,
401 GpuVector<int>
const &active_tensors, GpuVector<int>
const &active_num_points, GpuVector<int>
const &dim_offsets,
402 GpuVector<int>
const &map_tensor, GpuVector<int>
const &map_index, GpuVector<int>
const &map_reference, T *gpu_result);
409 void fillDataGPU(AccelerationContext
const *acc,
double value,
long long N,
long long stride,
double data[]);
415 template<
typename T>
void load_n(AccelerationContext
const *acc, T
const *cpu_data,
size_t num_entries, T *gpu_data);
421 template<
typename T,
typename U>
422 Utils::use_if<!std::is_same<U, T>::value> load_n(AccelerationContext
const *acc, U
const *cpu_data,
size_t num_entries, T *gpu_data){
423 std::vector<T> converted(num_entries);
424 std::transform(cpu_data, cpu_data + num_entries, converted.begin(), [](U
const &x)->T{ return static_cast<T>(x); });
425 load_n(acc, converted.data(), num_entries, gpu_data);
429 #ifdef __TASMANIAN_COMPILE_FALLBACK_CUDA_KERNELS__
435 void cudaDgemm(
int M,
int N,
int K,
const double *gpu_a,
const double *gpu_b,
double *gpu_c);
440 void cudaSparseMatmul(
int M,
int N,
int num_nz,
const int* gpu_spntr,
const int* gpu_sindx,
const double* gpu_svals,
const double *gpu_B,
double *gpu_C);
445 void cudaSparseVecDenseMat(
int M,
int N,
int num_nz,
const double *A,
const int *indx,
const double *vals,
double *C);
450 void convert_sparse_to_dense(
int num_rows,
int num_columns,
const int *gpu_pntr,
const int *gpu_indx,
const double *gpu_vals,
double *gpu_destination);
458namespace AccelerationMeta{
464 std::map<std::string, TypeAcceleration> getStringToAccelerationMap();
485 #ifdef Tasmanian_ENABLE_MAGMA
488 #ifdef Tasmanian_ENABLE_CUDA
492 #ifdef Tasmanian_ENABLE_HIP
496 #ifdef Tasmanian_ENABLE_DPCPP
500 #ifdef Tasmanian_ENABLE_BLAS
521 int getNumGpuDevices();
528 void setDefaultGpuDevice(
int deviceID);
535 unsigned long long getTotalGPUMemory(
int deviceID);
542 std::string getGpuDeviceName(
int deviceID);
547 template<
typename T>
void recvGpuArray(AccelerationContext
const*,
size_t num_entries,
const T *gpu_data, std::vector<T> &cpu_data);
552 template<
typename T>
void delGpuArray(AccelerationContext
const*, T *x);
558 void *createCublasHandle();
563 void deleteCublasHandle(
void *);
576struct AccelerationContext{
578 enum AlgorithmPreference{
609 AlgorithmPreference algorithm_select;
614 mutable std::unique_ptr<GpuEngine> engine;
618 #ifdef Tasmanian_ENABLE_BLAS
625 inline static constexpr int getDefaultAccDevice() {
626 #ifdef Tasmanian_ENABLE_DPCPP
634 AccelerationContext() : mode(getDefaultAccMode()), algorithm_select(algorithm_autoselect), device(getDefaultAccDevice()){}
637 ChangeType favorSparse(
bool favor){
638 #if __cplusplus > 201103L
639 AlgorithmPreference new_preference = [as=algorithm_select, favor]()->AlgorithmPreference{
641 return (as == algorithm_dense) ? algorithm_autoselect : algorithm_sparse;
643 return (as == algorithm_sparse) ? algorithm_autoselect : algorithm_dense;
647 AlgorithmPreference new_preference = [&]()->AlgorithmPreference{
649 return (algorithm_select == algorithm_dense) ? algorithm_autoselect : algorithm_sparse;
651 return (algorithm_select == algorithm_sparse) ? algorithm_autoselect : algorithm_dense;
655 if (new_preference != algorithm_select){
656 algorithm_select = new_preference;
657 return change_sparse_dense;
664 bool blasCompatible()
const{
665 #ifdef Tasmanian_ENABLE_BLAS
673 bool useKernels()
const{
674 #if defined(Tasmanian_ENABLE_CUDA) || defined(Tasmanian_ENABLE_HIP)
683 TypeAcceleration effective_acc = AccelerationMeta::getAvailableFallback(acc);
684 #ifdef Tasmanian_ENABLE_DPCPP
685 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < -1 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
686 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
688 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < 0 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
689 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
691 ChangeType mode_change = (effective_acc == mode) ? change_none : change_cpu_blas;
692 ChangeType device_change = (device == new_gpu_id) ? change_none : change_gpu_device;
695 return (AccelerationMeta::isAccTypeGPU(effective_acc)) ? device_change : change_gpu_device;
697 return (AccelerationMeta::isAccTypeGPU(effective_acc)) ? change_gpu_enabled : mode_change;
704 TypeAcceleration effective_acc = AccelerationMeta::getAvailableFallback(acc);
706 #ifdef Tasmanian_ENABLE_DPCPP
707 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < -1 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
708 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
710 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < 0 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
711 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
713 if (AccelerationMeta::isAccTypeGPU(effective_acc)){
716 if (!engine or new_gpu_id != device)
717 engine = Utils::make_unique<GpuEngine>();
723 mode = effective_acc;
727 void setDevice()
const{ AccelerationMeta::setDefaultGpuDevice(device); }
729 operator GpuEngine* ()
const{
return engine.get(); }
731 bool on_gpu()
const{
return !!engine; }
734#ifdef Tasmanian_ENABLE_DPCPP
748struct InternalSyclQueue{
750 InternalSyclQueue() : use_testing(false){}
752 void init_testing(
int gpuid);
754 operator std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>> (){
755 return std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>>(test_queue.get(),
756 HandleDeleter<AccHandle::Syclqueue>(
false));
761 std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>> test_queue;
770extern InternalSyclQueue test_queue;
TypeOneDRule
Used to specify the one dimensional family of rules that induces the sparse grid.
Definition tsgEnumerates.hpp:285
constexpr TypeAcceleration accel_gpu_rocblas
At the front API, the HIP and CUDA options are equivalent, see TasGrid::TypeAcceleration.
Definition tsgEnumerates.hpp:575
constexpr TypeAcceleration accel_gpu_hip
At the front API, the HIP and CUDA options are equivalent, see TasGrid::TypeAcceleration.
Definition tsgEnumerates.hpp:570
TypeAcceleration
Modes of acceleration.
Definition tsgEnumerates.hpp:551
@ accel_cpu_blas
Default (if available), uses both BLAS and LAPACK libraries.
Definition tsgEnumerates.hpp:555
@ accel_none
Usually the slowest mode, uses only OpenMP multi-threading, but optimized for memory and could be the...
Definition tsgEnumerates.hpp:553
@ accel_gpu_magma
Same the CUDA option but uses the UTK MAGMA library for the linear algebra operations.
Definition tsgEnumerates.hpp:563
@ accel_gpu_cublas
Mixed usage of the CPU (OpenMP) and GPU libraries.
Definition tsgEnumerates.hpp:559
@ accel_gpu_cuda
Similar to the cuBLAS option but also uses a set of Tasmanian custom GPU kernels.
Definition tsgEnumerates.hpp:561
Encapsulates the Tasmanian Sparse Grid module.
Definition TasmanianSparseGrid.hpp:68