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(std::exchange(other.num_entries, 0)), gpu_data(std::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() =
default;
122 GpuVector(AccelerationContext
const *acc,
size_t count){ resize(acc, count); }
132 GpuVector(AccelerationContext
const *acc,
int dim1,
int dim2){ resize(acc, Utils::size_mult(dim1, dim2)); }
134 GpuVector(AccelerationContext
const *acc,
const std::vector<T> &cpu_data){ load(acc, cpu_data); }
136 GpuVector(AccelerationContext
const *acc,
int dim1,
int dim2, T
const *cpu_data){ load(acc, Utils::size_mult(dim1, dim2), cpu_data); }
138 template<
typename IteratorLike>
139 GpuVector(AccelerationContext
const *acc, IteratorLike ibegin, IteratorLike iend) : GpuVector(){
140 load(acc, std::distance(ibegin, iend), std::addressof(*ibegin));
143 ~GpuVector(){ clear(); }
146 size_t size()
const{
return num_entries; }
148 T* data(){
return gpu_data; }
150 const T* data()
const{
return gpu_data; }
153 void resize(AccelerationContext
const *acc,
size_t count);
157 bool empty()
const{
return (num_entries == 0); }
163 void load(AccelerationContext
const *acc,
const std::vector<U> &cpu_data){
164 load(acc, cpu_data.size(), cpu_data.data());
176 void load(AccelerationContext
const *acc,
size_t count,
const U* cpu_data) {
177 if constexpr (std::is_same_v<U, T>) {
178 load_internal(acc, count, cpu_data);
181 std::vector<T> converted(count);
182 std::transform(cpu_data, cpu_data + count, converted.begin(), [](U
const &x)->T{ return static_cast<T>(x); });
183 load_internal(acc, count, converted.data());
188 void unload(AccelerationContext
const *acc, std::vector<T> &cpu_data)
const{
189 cpu_data.resize(num_entries);
190 unload(acc, cpu_data.data());
193 std::vector<T> unload(AccelerationContext
const *acc)
const{
199 void unload(AccelerationContext
const *acc,
size_t num, T* cpu_data)
const;
201 void unload(AccelerationContext
const *acc, T* cpu_data)
const{ unload(acc, num_entries, cpu_data); }
205 T* external = gpu_data;
212 using value_type = T;
223 void load_internal(AccelerationContext
const *acc,
size_t count,
const T* cpu_data);
225 size_t num_entries = 0;
226 T *gpu_data =
nullptr;
227 #ifdef Tasmanian_ENABLE_DPCPP
228 void* sycl_queue =
nullptr;
240 GpuEngine() =
default;
242 GpuEngine(GpuEngine
const &) =
delete;
244 GpuEngine &operator = (GpuEngine
const &) =
delete;
246 GpuEngine(GpuEngine &&) =
default;
248 GpuEngine &operator = (GpuEngine &&) =
default;
250 #ifdef Tasmanian_ENABLE_CUDA
252 void setCuBlasHandle(
void *handle);
254 void setCuSparseHandle(
void *handle);
256 void setCuSolverDnHandle(
void *handle);
259 std::unique_ptr<int, HandleDeleter<AccHandle::Cublas>> cublas_handle;
261 std::unique_ptr<int, HandleDeleter<AccHandle::Cusparse>> cusparse_handle;
263 std::unique_ptr<int, HandleDeleter<AccHandle::Cusolver>> cusolver_handle;
266 #ifdef Tasmanian_ENABLE_HIP
268 void setRocBlasHandle(
void *handle);
270 void setRocSparseHandle(
void *handle);
273 std::unique_ptr<int, HandleDeleter<AccHandle::Rocblas>> rblas_handle;
275 std::unique_ptr<int, HandleDeleter<AccHandle::Rocsparse>> rsparse_handle;
278 #ifdef Tasmanian_ENABLE_DPCPP
280 void setSyclQueue(
void *queue);
282 std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>> internal_queue;
286 bool called_magma_init =
false;
297class AccelerationDomainTransform{
300 AccelerationDomainTransform() =
default;
302 AccelerationDomainTransform(AccelerationContext
const *acc, std::vector<double>
const &transform_a, std::vector<double>
const &transform_b){
303 set(acc, transform_a, transform_b);
314 void getCanonicalPoints(
bool use01, T
const gpu_transformed_x[],
int num_x, GpuVector<T> &gpu_canonical_x);
316 operator bool ()
const {
return (acceleration !=
nullptr); }
318 void set(AccelerationContext
const *, std::vector<double>
const &transform_a, std::vector<double>
const &transform_b);
325 acceleration =
nullptr;
330 GpuVector<double> gpu_trans_a, gpu_trans_b;
331 int num_dimensions = 0, padded_size = 0;
332 AccelerationContext
const *acceleration =
nullptr;
356 void dtrans2can(AccelerationContext
const *acc,
bool use01,
int dims,
int num_x,
int pad_size,
357 const double *gpu_trans_a,
const double *gpu_trans_b,
358 const T *gpu_x_transformed, T *gpu_x_canonical);
373 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);
387 void devalpwpoly_sparse(AccelerationContext
const *acc,
int order,
TypeOneDRule rule,
int dims,
int num_x,
const T *gpu_x,
388 const GpuVector<T> &gpu_nodes,
const GpuVector<T> &gpu_support,
389 const GpuVector<int> &gpu_hpntr,
const GpuVector<int> &gpu_hindx,
const GpuVector<int> &gpu_hroots,
390 GpuVector<int> &gpu_spntr, GpuVector<int> &gpu_sindx, GpuVector<T> &gpu_svals);
405 void devalseq(AccelerationContext
const *acc,
int dims,
int num_x,
const std::vector<int> &max_levels,
const T *gpu_x,
406 const GpuVector<int> &num_nodes,
407 const GpuVector<int> &points,
const GpuVector<T> &nodes,
const GpuVector<T> &coeffs, T *gpu_result);
416 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);
427 void devalglo(AccelerationContext
const *acc,
bool is_nested,
bool is_clenshawcurtis0,
int dims,
int num_x,
int num_p,
int num_basis,
428 T
const *gpu_x, GpuVector<T>
const &nodes, GpuVector<T>
const &coeff, GpuVector<T>
const &tensor_weights,
429 GpuVector<int>
const &nodes_per_level, GpuVector<int>
const &offset_per_level, GpuVector<int>
const &map_dimension, GpuVector<int>
const &map_level,
430 GpuVector<int>
const &active_tensors, GpuVector<int>
const &active_num_points, GpuVector<int>
const &dim_offsets,
431 GpuVector<int>
const &map_tensor, GpuVector<int>
const &map_index, GpuVector<int>
const &map_reference, T *gpu_result);
438 void fillDataGPU(AccelerationContext
const *acc,
double value,
long long N,
long long stride,
double data[]);
444 template<
typename T>
void load_n_internal(AccelerationContext
const *acc, T
const *cpu_data,
size_t num_entries, T *gpu_data);
450 template<
typename T,
typename U>
451 void load_n(AccelerationContext
const *acc, U
const *cpu_data,
size_t num_entries, T *gpu_data){
452 if constexpr (std::is_same_v<U, T>) {
453 load_n_internal(acc, cpu_data, num_entries, gpu_data);
455 std::vector<T> converted(num_entries);
456 std::transform(cpu_data, cpu_data + num_entries, converted.begin(), [](U
const &x)->T{ return static_cast<T>(x); });
457 load_n_internal(acc, converted.data(), num_entries, gpu_data);
462 #ifdef __TASMANIAN_COMPILE_FALLBACK_CUDA_KERNELS__
468 void cudaDgemm(
int M,
int N,
int K,
const double *gpu_a,
const double *gpu_b,
double *gpu_c);
473 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);
478 void cudaSparseVecDenseMat(
int M,
int N,
int num_nz,
const double *A,
const int *indx,
const double *vals,
double *C);
483 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);
491namespace AccelerationMeta{
497 std::map<std::string, TypeAcceleration> getStringToAccelerationMap();
518 #ifdef Tasmanian_ENABLE_MAGMA
521 #ifdef Tasmanian_ENABLE_CUDA
525 #ifdef Tasmanian_ENABLE_HIP
529 #ifdef Tasmanian_ENABLE_DPCPP
533 #ifdef Tasmanian_ENABLE_BLAS
554 int getNumGpuDevices();
561 void setDefaultGpuDevice(
int deviceID);
568 unsigned long long getTotalGPUMemory(
int deviceID);
575 std::string getGpuDeviceName(
int deviceID);
580 template<
typename T>
void recvGpuArray(AccelerationContext
const*,
size_t num_entries,
const T *gpu_data, std::vector<T> &cpu_data);
585 template<
typename T>
void delGpuArray(AccelerationContext
const*, T *x);
591 void *createCublasHandle();
596 void deleteCublasHandle(
void *);
609struct AccelerationContext{
611 AccelerationContext(AccelerationContext
const &) =
delete;
613 AccelerationContext &operator = (AccelerationContext
const &) =
delete;
615 AccelerationContext(AccelerationContext &&) =
default;
617 AccelerationContext &operator = (AccelerationContext &&) =
default;
620 enum AlgorithmPreference{
651 AlgorithmPreference algorithm_select;
656 mutable std::optional<GpuEngine> engine;
660 #ifdef Tasmanian_ENABLE_BLAS
667 inline static constexpr int getDefaultAccDevice() {
668 #ifdef Tasmanian_ENABLE_DPCPP
676 AccelerationContext() : mode(getDefaultAccMode()), algorithm_select(algorithm_autoselect), device(getDefaultAccDevice()){}
679 ChangeType favorSparse(
bool favor){
680 AlgorithmPreference new_preference = [as=algorithm_select, favor]()->AlgorithmPreference{
682 return (as == algorithm_dense) ? algorithm_autoselect : algorithm_sparse;
684 return (as == algorithm_sparse) ? algorithm_autoselect : algorithm_dense;
687 if (new_preference != algorithm_select){
688 algorithm_select = new_preference;
689 return change_sparse_dense;
696 bool blasCompatible()
const{
697 #ifdef Tasmanian_ENABLE_BLAS
705 bool useKernels()
const{
706 #if defined(Tasmanian_ENABLE_CUDA) || defined(Tasmanian_ENABLE_HIP)
715 TypeAcceleration effective_acc = AccelerationMeta::getAvailableFallback(acc);
716 #ifdef Tasmanian_ENABLE_DPCPP
717 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < -1 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
718 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
720 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < 0 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
721 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
723 ChangeType mode_change = (effective_acc == mode) ? change_none : change_cpu_blas;
724 ChangeType device_change = (device == new_gpu_id) ? change_none : change_gpu_device;
727 return (AccelerationMeta::isAccTypeGPU(effective_acc)) ? device_change : change_gpu_device;
729 return (AccelerationMeta::isAccTypeGPU(effective_acc)) ? change_gpu_enabled : mode_change;
736 TypeAcceleration effective_acc = AccelerationMeta::getAvailableFallback(acc);
738 #ifdef Tasmanian_ENABLE_DPCPP
739 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < -1 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
740 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
742 if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < 0 or new_gpu_id >= AccelerationMeta::getNumGpuDevices())))
743 throw std::runtime_error(
"Invalid GPU device ID, see ./tasgrid -v for list of detected devices.");
745 if (AccelerationMeta::isAccTypeGPU(effective_acc)){
748 if (!engine or new_gpu_id != device)
755 mode = effective_acc;
759 void setDevice()
const{ AccelerationMeta::setDefaultGpuDevice(device); }
761 operator GpuEngine* ()
const{
return std::addressof(engine.value()); }
763 bool on_gpu()
const{
return !!engine; }
766#ifdef Tasmanian_ENABLE_DPCPP
780struct InternalSyclQueue{
782 InternalSyclQueue() =
default;
784 void init_testing(
int gpuid);
786 operator std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>> (){
787 return std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>>(test_queue.get(),
788 HandleDeleter<AccHandle::Syclqueue>(
false));
791 bool use_testing =
false;
793 std::unique_ptr<int, HandleDeleter<AccHandle::Syclqueue>> test_queue;
802extern InternalSyclQueue test_queue;
TypeOneDRule
Used to specify the one dimensional family of rules that induces the sparse grid.
Definition tsgEnumerates.hpp:288
constexpr TypeAcceleration accel_gpu_rocblas
At the front API, the HIP and CUDA options are equivalent, see TasGrid::TypeAcceleration.
Definition tsgEnumerates.hpp:578
constexpr TypeAcceleration accel_gpu_hip
At the front API, the HIP and CUDA options are equivalent, see TasGrid::TypeAcceleration.
Definition tsgEnumerates.hpp:573
TypeAcceleration
Modes of acceleration.
Definition tsgEnumerates.hpp:554
@ accel_cpu_blas
Default (if available), uses both BLAS and LAPACK libraries.
Definition tsgEnumerates.hpp:558
@ accel_none
Usually the slowest mode, uses only OpenMP multi-threading, but optimized for memory and could be the...
Definition tsgEnumerates.hpp:556
@ accel_gpu_magma
Same the CUDA option but uses the UTK MAGMA library for the linear algebra operations.
Definition tsgEnumerates.hpp:566
@ accel_gpu_cublas
Mixed usage of the CPU (OpenMP) and GPU libraries.
Definition tsgEnumerates.hpp:562
@ accel_gpu_cuda
Similar to the cuBLAS option but also uses a set of Tasmanian custom GPU kernels.
Definition tsgEnumerates.hpp:564
Encapsulates the Tasmanian Sparse Grid module.
Definition TasmanianSparseGrid.hpp:68