10#include "../feedback/feedback.h"
11#include "../global/global.h"
12#include "../utils/DeviceVector.h"
13#include "../utils/basic_structs.h"
14#include "../utils/error_handling.h"
15#include "../utils/gpu.hpp"
16#include "../utils/reduction_utilities.h"
21#ifndef FEEDBACK_LOG_INDIVIDUAL
22 #define FEEDBACK_LOG_INDIVIDUAL 0
25#define TPB_FEEDBACK 128
31namespace feedback_details
37 const part_int_t* id_dev;
38 const Real* pos_x_dev;
39 const Real* pos_y_dev;
40 const Real* pos_z_dev;
41 const Real* vel_x_dev;
42 const Real* vel_y_dev;
43 const Real* vel_z_dev;
76namespace feedback_details
80enum struct BoundaryStrategy {
81 excludeGhostParticle_ignoreStencilIssues,
85 excludeGhostParticle_snapActiveStencil
143namespace feedback_details
153 static_assert(std::is_trivially_copyable_v<T> and (!std::is_pointer_v<T>) and (!std::is_reference_v<T>));
164 CHOLLA_ASSERT(count > 0,
"count must be a positive integer");
165 GPU_Error_Check(cudaMalloc(&ptr_, count *
sizeof(T)));
171#if !((defined(__HIP_DEVICE_COMPILE__) && defined(O_HIP)) || (defined(__CUDA_ARCH__) && !defined(O_HIP)))
172 GPU_Error_Check(cudaDeviceSynchronize());
173 if (ptr_ !=
nullptr) GPU_Error_Check(cudaFree(ptr_));
187 __device__ __forceinline__ T& operator[](std::ptrdiff_t idx)
const noexcept {
return ptr_[idx]; }
190 __device__ __forceinline__ T& operator*()
const noexcept {
return *ptr_; }
193 __host__ __device__ __forceinline__ T* get()
const noexcept {
return ptr_; }
196 __host__ __device__ __forceinline__
explicit operator bool()
const noexcept {
return ptr_ !=
nullptr; }
202 this->ptr_ = other.ptr_;
208enum struct OverlapStrat {
247 OverlapStrat strat_ = OverlapStrat::ignore;
249 part_int_t pass_count_ = 0;
251 std::size_t mask_size_ = 0;
284 static inline constexpr part_int_t DFLT_VAL = 9223372036854775807;
288 : strat_(OverlapStrat::ignore),
291 curPass_mask_(
nullptr),
292 nextPass_mask_(
nullptr),
293 any_pending_particles_(
nullptr)
305 this->strat_ = strat;
306 std::size_t mask_size = ng_x * ng_y * ng_z;
309 case OverlapStrat::ignore:
311 this->pass_count_ = 0;
312 this->mask_size_ = 0;
313 this->curPass_mask_ =
nullptr;
314 this->nextPass_mask_ =
nullptr;
315 this->any_pending_particles_ =
nullptr;
317 case OverlapStrat::sequential:
318 this->pass_count_ = 0;
319 this->mask_size_ = mask_size;
334 __device__
void Reset_State(
const cooperative_groups::grid_group& g)
336 this->pass_count_ = 0;
338 if (this->strat_ != OverlapStrat::ignore) {
339 if (g.thread_rank() == 0) *(this->any_pending_particles_) = 0;
343 OverlapScheduler::clear_mask(this->nextPass_mask_.get(), this->mask_size_);
359 __device__
bool Prepare_Next_Pass(
const cooperative_groups::grid_group& g)
361 if (this->strat_ == OverlapStrat::ignore) {
362 if (this->pass_count_ != 0)
return false;
363 this->pass_count_ = 1;
374 if (0 == *(this->any_pending_particles_))
return false;
379 if (g.thread_rank() == 0) *(this->any_pending_particles_) = 0;
387 this->curPass_mask_.swap(this->nextPass_mask_);
388 OverlapScheduler::clear_mask(this->nextPass_mask_.get(), this->mask_size_);
401 template <
typename Prescription>
402 __device__
void Register_Pending_Particle_Feedback(Prescription p,
long long int particle_id,
405 if (strat_ == OverlapStrat::ignore)
return;
408 atomicMax(this->any_pending_particles_.get(), 1);
410 static_assert(
sizeof(
long long int) ==
sizeof(part_int_t));
411 long long int* mask = (
long long int*)(this->nextPass_mask_.get());
412 p.for_each_possible_overlap(
413 pos_indU[0], pos_indU[1], pos_indU[2], ng_x, ng_y,
414 [mask, particle_id](Real dummy_arg,
int ind3d) ->
void { atomicMin(mask + ind3d, particle_id); });
424 template <
typename Prescription>
425 __device__
bool Is_Scheduled_And_Update(Prescription p, part_int_t particle_id,
428 if (this->strat_ == OverlapStrat::ignore)
return true;
431 part_int_t min_id = OverlapScheduler::DFLT_VAL;
432 part_int_t* mask = this->curPass_mask_.get();
434 p.for_each_possible_overlap(
435 pos_indU[0], pos_indU[1], pos_indU[2], ng_x, ng_y,
436 [mask, &min_id](Real dummy_arg,
int ind3d) ->
void { min_id = min(min_id, mask[ind3d]); });
438 if (particle_id < min_id) {
440 }
else if (particle_id == min_id) {
444 Register_Pending_Particle_Feedback(p, particle_id, pos_indU, ng_x, ng_y);
456 static __device__
void clear_mask(part_int_t* ptr, std::size_t len)
458 len *= std::size_t(ptr !=
nullptr);
459 const std::size_t start = blockIdx.x * blockDim.x + threadIdx.x;
460 const std::size_t loop_stride = blockDim.x * gridDim.x;
461 for (
int i = start; i < len; i += loop_stride) {
462 ptr[i] = OverlapScheduler::DFLT_VAL;
471 const int n_ghost = spatial_props.n_ghost;
472 return {(particle_props.pos_x_dev[i] - spatial_props.xMin) / spatial_props.dx + n_ghost,
473 (particle_props.pos_y_dev[i] - spatial_props.yMin) / spatial_props.dy + n_ghost,
474 (particle_props.pos_z_dev[i] - spatial_props.zMin) / spatial_props.dz + n_ghost};
494template <
typename FeedbackModel, BoundaryStrategy BdryStrat>
498 int* num_SN_dev, OverlapScheduler ov_scheduler)
500 const int tid = threadIdx.x;
501 cooperative_groups::grid_group g = cooperative_groups::this_grid();
505 FeedbackModel fb_model{};
508 __shared__ Real s_info[FBInfoLUT::LEN * TPB_FEEDBACK];
509 for (
unsigned int cur_ind = 0; cur_ind < FBInfoLUT::LEN; cur_ind++) {
510 s_info[FBInfoLUT::LEN * tid + cur_ind] = 0;
516 auto checkDontSkip_and_maybeRevisePos = [&spatial_props, num_SN_dev](
int i,
518 const int n_ghost = spatial_props.n_ghost;
520 bool ignore = (((pos_indU[0] < n_ghost) or (pos_indU[0] >= (spatial_props.nx_g - n_ghost))) or
521 ((pos_indU[1] < n_ghost) or (pos_indU[1] >= (spatial_props.ny_g - n_ghost))) or
522 ((pos_indU[2] < n_ghost) or (pos_indU[2] >= (spatial_props.nz_g - n_ghost))));
525 if (BdryStrat == BoundaryStrategy::excludeGhostParticle_snapActiveStencil) {
530 pos_indU = FeedbackModel::nearest_noGhostOverlap_pos(pos_indU, spatial_props.nx_g, spatial_props.ny_g,
531 spatial_props.nz_g, n_ghost);
534 return (not ignore) and (num_SN_dev[i] > 0);
540 const int start = blockIdx.x * blockDim.x + threadIdx.x;
541 const int loop_stride = blockDim.x * gridDim.x;
544 ov_scheduler.Reset_State(g);
545 for (
int i = start; i < particle_props.n_local; i += loop_stride) {
550 if (checkDontSkip_and_maybeRevisePos(i, pos_indU)) {
551 ov_scheduler.Register_Pending_Particle_Feedback(fb_model, (
long long int)(particle_props.id_dev[i]), pos_indU,
552 spatial_props.nx_g, spatial_props.ny_g);
557 while (ov_scheduler.Prepare_Next_Pass(g)) {
560 for (
int i = start; i < particle_props.n_local; i += loop_stride) {
565 if (checkDontSkip_and_maybeRevisePos(i, pos_indU)) {
566 bool is_scheduled = ov_scheduler.Is_Scheduled_And_Update(fb_model, particle_props.id_dev[i], pos_indU,
567 spatial_props.nx_g, spatial_props.ny_g);
571 const Real age = cycle_props.
t - particle_props.age_dev[i];
574 Real& mass_ref = particle_props.mass_dev[i];
576#if FEEDBACK_LOG_INDIVIDUAL
579 "...feedback-log-individual:\n"
580 " {\"block\": %d, \"thread\":%d, \"cycle\":%d,\n"
581 " \"index\": %d, \"id\": %lld, \"age\": %g,\n"
582 " \"mass (pre-feedback)\": %g, num_SN: %d\n"
583 " \"position (code units)\": [%g, %g, %g],\n"
584 " \"position (index-units)\": [%g, %g, %g],\n"
585 " \"vel (code-units)\": [%g, %g, %g]}\n",
586 blockIdx.x, threadIdx.x, cycle_props.
n_step, i, (
long long int)(particle_props.id_dev[i]), age, mass_ref,
587 num_SN_dev[i], particle_props.pos_x_dev[i], particle_props.pos_y_dev[i], particle_props.pos_z_dev[i],
588 pos_indU[0], pos_indU[1], pos_indU[2], particle_props.vel_x_dev[i], particle_props.vel_y_dev[i],
589 particle_props.vel_z_dev[i]);
590 int pre_countResolved = s_info[FBInfoLUT::countResolved];
593 fb_model.apply_feedback(pos_indU[0], pos_indU[1], pos_indU[2], particle_props.vel_x_dev[i],
594 particle_props.vel_y_dev[i], particle_props.vel_z_dev[i], age, mass_ref,
595 particle_props.id_dev[i], spatial_props.dx, spatial_props.dy, spatial_props.dz,
596 spatial_props.nx_g, spatial_props.ny_g, spatial_props.nz_g, spatial_props.n_ghost,
597 num_SN_dev[i], cycle_props.
n_step, s_info, conserved_dev);
599#if FEEDBACK_LOG_INDIVIDUAL
602 "...feedback-log-individual-extra: {\"block\": %d, \"thread\":%d, \"cycle\":%d, \"id\": %lld, "
603 "\"isResolved\": %d}\n",
604 blockIdx.x, threadIdx.x, cycle_props.
n_step, (
long long int)(particle_props.id_dev[i]),
605 int(s_info[FBInfoLUT::countResolved] > pre_countResolved));
615 reduction_utilities::blockAccumulateIntoNReals<FBInfoLUT::LEN, TPB_FEEDBACK>(info, s_info);
635template <
typename FeedbackModel, BoundaryStrategy BdryStrat>
636KernelAndLaunchConf fetch_kernel_and_launch_conf_(
int threads_per_block,
int max_num_threadblocks,
637 std::size_t dynamic_shared_mem_per_block)
646 const dim3 dimBlock(threads_per_block, 1, 1);
649 static int last_max_num_threadblocks = 0;
650 static int last_threads_per_block = 0;
651 static std::size_t last_dynamic_shared_mem_per_block = 0;
653 CHOLLA_ASSERT(max_num_threadblocks > 0,
"max_num_threadblocks must be positive!");
654 if ((last_max_num_threadblocks != max_num_threadblocks) or (last_threads_per_block != threads_per_block) or
655 (last_dynamic_shared_mem_per_block != dynamic_shared_mem_per_block)) {
656 last_max_num_threadblocks = max_num_threadblocks;
657 last_threads_per_block = threads_per_block;
658 last_dynamic_shared_mem_per_block = dynamic_shared_mem_per_block;
661 int supportsCoopLaunch = 0;
662 cudaError err = cudaDeviceGetAttribute(&supportsCoopLaunch, cudaDevAttrCooperativeLaunch, dev);
663 CHOLLA_ASSERT(cudaSuccess == err,
664 "Error encountered within cudaDeviceGetAttribute while querying whether the "
665 "system supports cooperative kernels");
666 CHOLLA_ASSERT(supportsCoopLaunch != 0,
"System is unable to launch cooperative kernels");
668 cudaDeviceProp deviceProp;
669 cudaGetDeviceProperties(&deviceProp, dev);
670 int numBlocksPerSm = 0;
671 err = cudaOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocksPerSm,
672 Cluster_Feedback_Kernel<FeedbackModel, BdryStrat>,
673 threads_per_block, dynamic_shared_mem_per_block);
674 CHOLLA_ASSERT(cudaSuccess == err,
675 "Error encountered within cudaOccupancyMaxActiveBlocksPerMultiprocessor while "
676 "querying whether the max active blocks per SM");
677 CHOLLA_ASSERT(numBlocksPerSm > 0,
"Something is wrong! The number of blocks per SM should be positive");
679 dimGrid = dim3(std::min(deviceProp.multiProcessorCount * numBlocksPerSm, max_num_threadblocks), 1, 1);
682 return KernelAndLaunchConf{(
void*)Cluster_Feedback_Kernel<FeedbackModel, BdryStrat>, dimBlock, dimGrid};
703template <
typename FeedbackModel>
707 int* num_SN_dev, OverlapScheduler& ov_scheduler, BoundaryStrategy bdry_strat,
708 int max_num_threadblocks = INT_MAX)
714 const std::size_t dynamic_shared_mem_per_block = 0;
715 const int threads_per_block = TPB_FEEDBACK;
717 KernelAndLaunchConf tmp;
718 switch (bdry_strat) {
719 case BoundaryStrategy::excludeGhostParticle_ignoreStencilIssues:
720 tmp = fetch_kernel_and_launch_conf_<FeedbackModel, BoundaryStrategy::excludeGhostParticle_ignoreStencilIssues>(
721 threads_per_block, max_num_threadblocks, dynamic_shared_mem_per_block);
723 case BoundaryStrategy::excludeGhostParticle_snapActiveStencil:
724 tmp = fetch_kernel_and_launch_conf_<FeedbackModel, BoundaryStrategy::excludeGhostParticle_snapActiveStencil>(
725 threads_per_block, max_num_threadblocks, dynamic_shared_mem_per_block);
729 "Unable to handle specified bdry_strat. This probably means a new stategy "
730 "was introduced without modifying the switch-statement this error occurs in.");
734 Real* d_info_ptr = d_info.data();
735 void* kernelArgs[] = {(
void*)(&particle_props), (
void*)(&spatial_props), (
void*)(&cycle_props), (
void*)(&d_info_ptr),
736 (
void*)(&conserved_dev), (
void*)(&num_SN_dev), (
void*)(&ov_scheduler)};
738 cudaLaunchCooperativeKernel((
void*)tmp.kernel_ptr, tmp.dim_grid, tmp.dim_block, kernelArgs,
739 dynamic_shared_mem_per_block, 0);
750 if (info !=
nullptr) {
752 GPU_Error_Check(cudaMemcpy(info, d_info.data(), FBInfoLUT::LEN *
sizeof(Real), cudaMemcpyDeviceToHost));
754 GPU_Error_Check(cudaDeviceSynchronize());
A templatized class to encapsulate a device global memory pointer in a std::vector like interface com...
Definition DeviceVector.h:45
Real t
Definition kernel.h:67
int n_step
Definition kernel.h:69
Real dt
Definition kernel.h:68
A data only struct that acts as a simple 3 element vector.
Definition basic_structs.h:32