14#ifndef GRID_GPU_CONTEXT_H
15#define GRID_GPU_CONTEXT_H
18#include <hip/hip_runtime_api.h>
20#include <cuda_runtime.h>
26#include "../common/grid_basis_set.h"
27#include "../common/grid_constants.h"
30#include "../../offload/offload_library.h"
31#include "../../offload/offload_runtime.h"
38inline size_t round_up16(
size_t n) {
return (n + 15) & ~size_t(15); }
42 size_t allocated_size_{0};
43 size_t current_size_{0};
44 bool internal_allocation_{
false};
45 T *device_ptr_{
nullptr};
46 T *host_ptr_{
nullptr};
49 allocated_size_ = other.allocated_size_;
50 current_size_ = other.current_size_;
51 internal_allocation_ = other.internal_allocation_;
52 device_ptr_ = other.device_ptr_;
53 host_ptr_ = other.host_ptr_;
55 other.allocated_size_ = 0;
56 other.current_size_ = 0;
57 other.internal_allocation_ =
false;
58 other.device_ptr_ =
nullptr;
59 other.host_ptr_ =
nullptr;
73 move_from(std::move(other));
80 allocated_size_ = (size__ < 16) ? 16 :
round_up16(size__);
81 current_size_ = size__;
82 internal_allocation_ =
true;
84#ifndef __OFFLOAD_UNIFIED_MEMORY
85 offloadMalloc((
void **)&device_ptr_,
sizeof(T) * allocated_size_);
87 hipMallocManaged((
void **)&device_ptr_,
sizeof(T) * allocated_size_);
89 assert(device_ptr_ !=
nullptr);
93 allocated_size_ = size__;
94 current_size_ = size__;
95 internal_allocation_ =
false;
96 device_ptr_ =
static_cast<T *
>(ptr__);
100 inline size_t size()
const {
return current_size_; }
103 assert(device_ptr_ !=
nullptr);
104 assert(data__ !=
nullptr);
105 offloadMemcpyHtoD(device_ptr_, data__,
sizeof(T) * current_size_);
108 inline void copy_to_gpu(
const T *data__, offloadStream_t &stream__) {
109 assert(device_ptr_ !=
nullptr);
110 assert(data__ !=
nullptr);
111 offloadMemcpyAsyncHtoD(device_ptr_, data__,
sizeof(T) * current_size_,
116 assert(device_ptr_ !=
nullptr);
117 assert(host_ptr_ !=
nullptr);
121 offloadMemcpyAsyncHtoD(device_ptr_, host_ptr_,
sizeof(T) * current_size_,
126 assert(device_ptr_ !=
nullptr);
127 assert(data__ !=
nullptr);
128 offloadMemcpyAsyncDtoH(data__, device_ptr_,
sizeof(T) * current_size_,
133 assert(device_ptr_ !=
nullptr);
134 assert(host_ptr_ !=
nullptr);
138 offloadMemcpyAsyncDtoH(host_ptr_, device_ptr_,
sizeof(T) * current_size_,
142 inline void zero(offloadStream_t &stream__) {
143 assert(device_ptr_ !=
nullptr);
145 offloadMemsetAsync(device_ptr_, 0,
sizeof(T) * current_size_, stream__);
148 inline void associate(
void *host_ptr__,
void *device_ptr__,
149 const size_t size__) {
150 assert(host_ptr__ !=
nullptr);
151 assert(device_ptr__ !=
nullptr);
153 internal_allocation_ =
false;
154 allocated_size_ = size__;
155 current_size_ = size__;
156 device_ptr_ =
static_cast<T *
>(device_ptr__);
157 host_ptr_ =
static_cast<T *
>(host_ptr__);
162 offloadMemset(device_ptr_, 0,
sizeof(T) * current_size_);
166 assert(data__.size() == current_size_);
171 assert(device_ptr_ !=
nullptr);
172 offloadMemcpyHtoD(device_ptr_, data__.data(),
sizeof(T) * data__.size());
175 inline void resize(
const size_t new_size__) {
176 if (!internal_allocation_) {
178 device_ptr_ =
nullptr;
182 assert(new_size__ != 0);
183 if (allocated_size_ < new_size__) {
184 if (internal_allocation_ && device_ptr_ !=
nullptr)
185 offloadFree(device_ptr_);
186 device_ptr_ =
nullptr;
187 allocated_size_ = (new_size__ < 16) ? 16 :
round_up16(new_size__);
188 offloadMalloc((
void **)&device_ptr_,
sizeof(T) * allocated_size_);
189 internal_allocation_ =
true;
192 assert(device_ptr_ !=
nullptr);
193 current_size_ = new_size__;
197 inline void clear() { current_size_ = 0; }
201 if (internal_allocation_ && (device_ptr_ !=
nullptr)) {
202 offloadFree(device_ptr_);
207 device_ptr_ =
nullptr;
209 internal_allocation_ =
false;
212 inline T *
data() {
return device_ptr_; }
213 inline const T *
data()
const {
return device_ptr_; }
223 std::array<T, 9> dh_;
224 std::array<T, 9> dh_inv_;
225 bool orthogonal_{
false};
226 bool is_distributed_{
false};
238 grid_info(
const int *full_size__,
const int *local_size__,
239 const int *border_width__) {
240 int roffset__[3] = {0, 0, 0};
241 initialize(full_size__, local_size__, roffset__, border_width__);
247 assert(
data !=
nullptr);
261 inline void resize(
const int *full_size__,
const int *local_size__,
262 const int *
const roffset__,
263 const int *
const border_width__) {
264 initialize(full_size__, local_size__, roffset__, border_width__);
267 inline size_t size()
const {
return grid_.
size(); }
269 inline void zero(offloadStream_t &stream) { grid_.
zero(stream); }
272 for (
int i = 0;
i < 9; ++
i) {
274 dh_inv_[
i] = dh_inv__[
i];
279 is_distributed_ = distributed__;
288 T norm1, norm2, norm3;
289 bool orthogonal[3] = {
false,
false,
false};
290 norm1 = dh_[0] * dh_[0] + dh_[1] * dh_[1] + dh_[2] * dh_[2];
291 norm2 = dh_[3] * dh_[3] + dh_[4] * dh_[4] + dh_[5] * dh_[5];
292 norm3 = dh_[6] * dh_[6] + dh_[7] * dh_[7] + dh_[8] * dh_[8];
294 norm1 = 1.0 / sqrt(norm1);
295 norm2 = 1.0 / sqrt(norm2);
296 norm3 = 1.0 / sqrt(norm3);
300 ((fabs(dh_[0] * dh_[6] + dh_[1] * dh_[7] + dh_[2] * dh_[8]) * norm1 *
304 ((fabs(dh_[3] * dh_[6] + dh_[4] * dh_[7] + dh_[5] * dh_[8]) * norm2 *
308 ((fabs(dh_[0] * dh_[3] + dh_[1] * dh_[4] + dh_[2] * dh_[5]) * norm1 *
311 orthogonal_ = orthogonal[0] && orthogonal[1] && orthogonal[2];
315 assert(data__ !=
nullptr);
323 inline void associate(
void *host_ptr__,
void *device_ptr__,
324 const size_t size__) {
325 assert(host_ptr__ !=
nullptr);
326 assert(device_ptr__ !=
nullptr);
327 grid_.
associate(host_ptr__, device_ptr__, size__);
340 inline const T *
data()
const {
return grid_.
data(); }
345 inline T *
dh() {
return dh_.data(); }
346 inline const T *
dh()
const {
return dh_.data(); }
348 inline T *
dh_inv() {
return dh_inv_.data(); }
349 inline const T *
dh_inv()
const {
return dh_inv_.data(); }
355 void initialize(
const int *
const full_size__,
const int *
const local_size__,
356 const int *
const roffset__,
const int *
const border_width__) {
360 full_size_.x = full_size__[0];
361 full_size_.y = full_size__[1];
362 full_size_.z = full_size__[2];
364 local_size_.x = local_size__[0];
365 local_size_.y = local_size__[1];
366 local_size_.z = local_size__[2];
368 lower_corner_.x = roffset__[0];
369 lower_corner_.y = roffset__[1];
370 lower_corner_.z = roffset__[2];
372 is_distributed_ = (full_size_.x != local_size_.x) ||
373 (full_size_.y != local_size_.y) ||
374 (full_size_.z != local_size_.z);
376 border_width_.x = border_width__[0];
377 border_width_.y = border_width__[1];
378 border_width_.z = border_width__[2];
491 std::vector<grid_info<double>>
grid_;
505 device_id_ = (device_id__ < 0) ? 0 : device_id__;
516 : device_id_{other.device_id_}, lmax_{other.lmax_},
520 sphi{std::move(other.sphi)},
526 cab_dev_{std::move(other.cab_dev_)},
529 forces_{std::move(other.forces_)},
virial_{std::move(other.virial_)},
532 grid_{std::move(other.grid_)},
536 sphi_dev{std::move(other.sphi_dev)},
545 for (
int i = 0;
i < 2; ++
i)
546 for (
int j = 0; j < 20; ++j)
547 stats[
i][j] = other.stats[
i][j];
550 other.device_id_ = -1;
558 other.main_stream = {};
559 other.calculate_forces =
false;
560 other.calculate_virial =
false;
561 other.compute_tau =
false;
562 other.apply_border_mask =
false;
566 if (
this != &other) {
569 device_id_ = other.device_id_;
577 sphi = std::move(other.sphi);
581 for (
int i = 0;
i < 2; ++
i)
582 for (
int j = 0; j < 20; ++j)
583 stats[
i][j] = other.stats[
i][j];
588 cab_dev_ = std::move(other.cab_dev_);
591 forces_ = std::move(other.forces_);
592 virial_ = std::move(other.virial_);
595 grid_ = std::move(other.grid_);
599 sphi_dev = std::move(other.sphi_dev);
609 other.device_id_ = -1;
617 other.main_stream = {};
618 other.calculate_forces =
false;
619 other.calculate_virial =
false;
620 other.compute_tau =
false;
621 other.apply_border_mask =
false;
627 if (device_id_ >= 0) {
628 offload_set_chosen_device(device_id_);
629 offload_activate_chosen_device();
643 for (
auto &phi :
sphi) {
656 offloadStreamDestroy(stream);
660 for (
auto &g :
grid_) {
666 int lmax()
const {
return lmax_; }
669 const int nkinds__) {
671 if (nkinds__ > (
int)
sphi.size()) {
672 for (
auto &phi :
sphi)
673 if (phi !=
nullptr) {
679 sphi.resize(nkinds__,
nullptr);
686 for (
int i = 0;
i < nkinds__;
i++) {
687 const auto &basis_set = basis_sets[
i];
688 if (
sphi_size[
i] < basis_set->nsgf * basis_set->maxco) {
689 offloadMalloc((
void **)&
sphi[
i],
690 basis_set->nsgf * basis_set->maxco *
sizeof(
double));
691 sphi_size[
i] = basis_set->nsgf * basis_set->maxco;
694 offloadMemcpyHtoD(
sphi[
i], basis_set->sphi,
695 basis_set->nsgf * basis_set->maxco *
sizeof(
double));
700 for (
int ikind = 0; ikind <
nkinds; ikind++) {
701 for (
int iset = 0; iset < basis_sets[ikind]->
nset; iset++) {
702 lmax_ = std::max(lmax_, basis_sets[ikind]->
lmax[iset]);
715 offloadStreamCreate(&stream);
721 offloadStreamSynchronize(stream);
726 offloadDeviceSynchronize();
730 offload_set_chosen_device(device_id_);
731 offload_activate_chosen_device();
743 fprintf(stderr,
"This object does not seem to have the right structure.\n"
744 "A casting went wrong or the object is corrupted\n");
753 unsigned int compute_checksum_() {
std::vector< int > first_task_per_level_
void calculate_all_coefficients(const enum grid_func func, int *lp_diff)
gpu_vector< double > virial_
gpu_vector< int > sorted_blocks_offset_dev
gpu_vector< double > coef_dev_
gpu_vector< int > cab_block_offset_dev
std::vector< int > sphi_size
gpu_vector< double > pab_block_
void collocate_one_grid_level(const int level, const enum grid_func func, int *lp_diff)
Launches the Cuda kernel that collocates all tasks of one grid level.
gpu_vector< int > block_offsets_dev
offloadStream_t main_stream
void synchronize(offloadStream_t &stream)
context_info(context_info &&other) noexcept
gpu_vector< double > cab_dev_
gpu_vector< task_info > tasks_dev
context_info & operator=(const context_info &)=delete
std::vector< grid_info< double > > grid_
gpu_vector< double > forces_
context_info(int device_id__)
void compute_hab_coefficients()
gpu_vector< double > hab_block_
std::vector< double * > sphi
std::vector< offloadStream_t > level_streams
void initialize_basis_sets(const grid_basis_set **basis_sets, const int nkinds__)
std::vector< int > number_of_tasks_per_level_
gpu_vector< double * > sphi_dev
context_info & operator=(context_info &&other) noexcept
gpu_vector< int > num_tasks_per_block_dev_
context_info(const context_info &)=delete
void integrate_one_grid_level(const int level, int *lp_diff)
Launches the Cuda kernel that integrates all tasks of one grid level.
gpu_vector< int > task_sorted_by_blocks_dev
gpu_vector & operator=(gpu_vector &&other) noexcept
void zero(offloadStream_t &stream__)
void copy_associated_host_to_gpu(offloadStream_t &stream__)
gpu_vector(const size_t size__)
void resize(const size_t new_size__)
void copy_from_gpu(T *data__, offloadStream_t &stream__)
void copy_gpu_to_associated_host(offloadStream_t &stream__)
void associate(void *host_ptr__, void *device_ptr__, const size_t size__)
gpu_vector(const size_t size__, void *ptr__)
void copy_to_gpu(const std::vector< T > &data__)
void copy_to_gpu(const T *data__, offloadStream_t &stream__)
gpu_vector & operator=(const gpu_vector &)=delete
gpu_vector(const gpu_vector &)=delete
void copy_to_gpu(const T *data__)
gpu_vector(gpu_vector &&other) noexcept
bool is_distributed() const
void zero(offloadStream_t &stream)
grid_info(grid_info &&) noexcept=default
void copy_to_gpu(const T *data, offloadStream_t &stream)
void check_orthogonality(const bool ortho)
Check if the lattice vectors form a orthogonal basis.
void copy_to_host(T *data__, offloadStream_t &stream)
bool is_orthogonal() const
grid_info & operator=(const grid_info &)=delete
grid_info(const grid_info &)=delete
void copy_to_gpu(offloadStream_t &stream)
void copy_to_host(offloadStream_t &stream)
void resize(const int *full_size__, const int *local_size__, const int *const roffset__, const int *const border_width__)
const gpu_vector< T > & grid() const
void associate(void *host_ptr__, void *device_ptr__, const size_t size__)
grid_info(const int *full_size__, const int *local_size__, const int *border_width__)
void is_distributed(const bool distributed__)
void set_lattice_vectors(const T *dh__, const T *dh_inv__)
static void const int const int i
size_t round_up16(size_t n)
Internal representation of a basis set.
Device buffers used by the collocate and integrate kernels. Which fields are non-null depends on whic...
Parameters of the collocate kernel.
int * task_sorted_by_blocks_dev
int * cab_block_offset_dev
kernel_buffers buffers_dev
int * num_tasks_per_block_dev
int * sorted_blocks_offset_dev
Internal representation of a task.