1#ifndef AMREX_FB_UNPACK_ON_ARRIVAL_H_
2#define AMREX_FB_UNPACK_ON_ARRIVAL_H_
18#ifdef AMREX_FB_UNPACK_ON_ARRIVAL
27template <
typename BUF,
typename T,
bool ADD,
bool ATOMIC>
28struct FBOnArrivalUnpack {
34 void operator() (
int icell,
int ncells,
int i,
int j,
int k,
35 CommRecvBufTag<T>
const& tag)
const noexcept
38 Array4<BUF const> sfab{(BUF
const*)(dbase + tag.poff),
40 for (
int n = 0; n < ncomp; ++n) {
41 if constexpr (ADD && ATOMIC) {
42 Gpu::Atomic::AddNoRet(&tag.dfab(i,j,k,n+dcomp), (T)sfab(i,j,k,n));
43 }
else if constexpr (ADD) {
44 tag.dfab(i,j,k,n+dcomp) += (T)sfab(i,j,k,n);
46 tag.dfab(i,j,k,n+dcomp) = (T)sfab(i,j,k,n);
53template <
typename BUF,
typename T>
54void fb_oa_pack (TagVector<CommSendBufTag<T>>
const& tv,
char* dbase,
int scomp,
int ncomp)
56 detail::ParallelFor_doit(tv,
58 int icell,
int ncells,
int i,
int j,
int k, CommSendBufTag<T>
const& tag)
noexcept
63 for (
int n = 0; n < ncomp; ++n) {
64 dfab(i,j,k,n) = (BUF)tag.sfab(i,j,k,n+scomp);
72struct FBOnArrivalWarpRanges {
73 static constexpr int max_ranges = 16;
74 int begin[max_ranges] = {0};
75 int prefix[max_ranges+1] = {0};
79 bool add (
int b,
int nw)
noexcept {
80 if (n > 0 && begin[n-1] + (prefix[n]-prefix[n-1]) == b) {
82 }
else if (n < max_ranges) {
84 prefix[n+1] = prefix[n] + nw;
93template <
typename T,
typename F>
94void fb_oa_unpack_ranges (TagVector<CommRecvBufTag<T>>
const& tv,
95 FBOnArrivalWarpRanges
const& r,
F const& f)
97 const int nwarps = r.prefix[r.n];
98 if (nwarps == 0) {
return; }
100 constexpr int nthreads = TagVector<CommRecvBufTag<T>>::nthreads;
102 const int nblocks = (nwarps + nwarps_per_block-1) / nwarps_per_block;
103 const auto d_tags = tv.d_tags;
104 const auto d_nwarps = tv.d_nwarps;
105 const auto ntags = tv.ntags;
110 [[sycl::reqd_work_group_size(nthreads)]]
117 std::size_t g_tid = item.get_global_id(0);
119 auto g_tid = std::size_t(blockDim.x)*blockIdx.x + threadIdx.x;
122 if (l_wid >= nwarps) {
return; }
124 int g_wid = r.begin[ir] + (l_wid - r.prefix[ir]);
126 int b_wid = g_wid - d_nwarps[tag_id];
133 tagparfor_call_f(icell, d_tags[tag_id], f);
141template <
typename BUF>
145 RecvSendCopyHandlerKey key{TheFB.m_id,
sizeof(BUF), ncomp};
146 if (
auto it = m_fb_on_arrival_meta.find(key); it != m_fb_on_arrival_meta.end()) {
147 return it->second.get();
150 if (m_fb_on_arrival_meta.size() >= 32) { m_fb_on_arrival_meta.clear(); }
152 auto e = std::make_unique<FBOnArrivalMeta<FAB>>();
154 auto make_layout = [&] (MapOfCopyComTagContainers
const& tags,
bool is_send,
157 for (
auto const& [rank, cctc] : tags) {
158 std::size_t nbytes = 0;
159 for (
auto const& cct : cctc) {
160 nbytes += (is_send ? cct.sbox : cct.dbox).numPts() * ncomp *
sizeof(BUF);
162 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
165 lo.rank.push_back(rank);
166 lo.size.push_back(nbytes);
167 lo.offset.push_back(lo.nbytes);
172 make_layout(*TheFB.m_SndTags,
true, e->snd);
173 make_layout(*TheFB.m_RcvTags,
false, e->rcv);
178 for (
auto const& kv : *TheFB.m_SndTags) {
179 auto off =
static_cast<std::ptrdiff_t
>(e->snd.offset[m]);
180 for (
auto const& cct : kv.second) {
182 .sfab = this->const_array(cct.srcIndex),
183 .poff = off, .bx = cct.sbox});
184 off += cct.sbox.numPts() * ncomp *
sizeof(BUF);
188 e->send_tv.define(tags);
195 e->rcv_warp_begin.push_back(0);
197 for (
auto const& kv : *TheFB.m_RcvTags) {
198 auto off =
static_cast<std::ptrdiff_t
>(e->rcv.offset[m]);
199 int nwarps = e->rcv_warp_begin.back();
200 for (
auto const& cct : kv.second) {
201 const int li = this->localindex(cct.dstIndex);
203 .dfab = this->atLocalIdx(li).array(),
204 .poff = off, .bx = cct.dbox});
205 off += cct.dbox.numPts() * ncomp *
sizeof(BUF);
206 nwarps +=
static_cast<int>((detail::get_tag_size(tags.back())
210 e->rcv_warp_begin.push_back(nwarps);
213 e->recv_tv.define(tags);
218 m_fb_on_arrival_meta[key] = std::move(e);
223template <
typename BUF>
228 auto* e = FB_on_arrival_meta<BUF>(TheFB, ncomp);
230 const int N_locs = TheFB.m_LocTags->size();
231 const auto N_rcvs =
static_cast<int>(e->rcv.rank.size());
232 const auto N_snds =
static_cast<int>(e->snd.rank.size());
234 fbd = std::make_unique<FBData<FAB>>();
241 auto alloc = [] (std::size_t n) {
244 fbd->the_recv_data = alloc(e->rcv.nbytes);
245 fbd->the_send_data = alloc(e->snd.nbytes);
252 fbd->recv_stat.resize(N_rcvs);
253 for (
int i = 0; i < N_rcvs; ++i) {
254 if (e->rcv.size[i] > 0) {
257 (fbd->the_recv_data + e->rcv.offset[i], e->rcv.size[i],
258 rank, SeqNum, comm).
req();
266 detail::fb_oa_pack<BUF>(e->send_tv, fbd->the_send_data, scomp, ncomp);
271 for (
int j = 0; j < N_snds; ++j) {
272 if (e->snd.size[j] > 0) {
275 (fbd->the_send_data + e->snd.offset[j], e->snd.size[j],
276 rank, SeqNum, comm).
req();
281 if (N_rcvs > 0) { FillBoundary_test(); }
285 if constexpr (amrex::IsAddAssignable<value_type>::value) {
287 FB_local_add_gpu(TheFB, scomp, ncomp,
false);
291 FB_local_copy_gpu(TheFB, scomp, ncomp);
293 if (N_rcvs > 0) { FillBoundary_test(); }
298template <
typename BUF>
302 auto* e = fbd->oa_meta;
303 const FB* TheFB = fbd->fb;
304 const auto N_rcvs =
static_cast<int>(e->rcv.rank.size());
305 const auto N_snds =
static_cast<int>(e->snd.rank.size());
308 const bool sumboundary = TheFB->m_sb_snghost.allGE(0);
311 const bool on_arrival = e->rcv.nbytes >=
313 auto unpack = [&] (
auto const& f) {
320 detail::ParallelFor_doit(e->recv_tv, f);
326 detail::FBOnArrivalWarpRanges ranges;
327 auto flush = [&] () {
330 detail::fb_oa_unpack_ranges(e->recv_tv, ranges, f);
334 auto add = [&] (
int m) {
335 const int b = e->rcv_warp_begin[m];
336 const int nw = e->rcv_warp_begin[m+1] - b;
337 if (nw > 0 && !ranges.add(b, nw)) {
342 for (
int m = 0; m < N_rcvs; ++m) {
353 if (completed == MPI_UNDEFINED || completed == 0) {
break; }
354 std::sort(indx.begin(), indx.begin()+completed);
355 for (
int c = 0; c < completed; ++c) { add(indx[c]); }
360 using T = value_type;
362 if constexpr (amrex::IsAddAssignable<T>::value) {
363 if (TheFB->m_threadsafe_rcv) {
364 unpack(detail::FBOnArrivalUnpack<BUF,T,true,false>
365 {fbd->the_recv_data, fbd->scomp, fbd->ncomp});
366 }
else if constexpr (amrex::HasAtomicAdd<T>::value) {
367 unpack(detail::FBOnArrivalUnpack<BUF,T,true,true>
368 {fbd->the_recv_data, fbd->scomp, fbd->ncomp});
370 amrex::Abort(
"FB_on_arrival_finish: SumBoundary needs thread-safe tags or atomic add");
374 unpack(detail::FBOnArrivalUnpack<BUF,T,false,false>
375 {fbd->the_recv_data, fbd->scomp, fbd->ncomp});
385 if (fbd->the_recv_data) {
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:593
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
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.
static Long m_fb_on_arrival_min_bytes
Definition AMReX_FabArrayBase.H:889
FBOnArrivalMeta< FAB > * FB_on_arrival_meta(const FB &TheFB, int ncomp)
void FB_on_arrival_nowait(const FB &TheFB, int scomp, int ncomp, int SeqNum, bool sumboundary)
void FB_on_arrival_finish()
static constexpr int warp_size
Definition AMReX_GpuDevice.H:239
MPI_Request req() const
Definition AMReX_ParallelDescriptor.H:74
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
amrex_long Long
Definition AMReX_INT.H:30
ArrayND< T, 4, true > Array4
Convenient alias for a 4D ArrayND with three spatial dimensions plus a component dimension.
Definition AMReX_Array4.H:1340
Arena * The_Comms_Arena()
Definition AMReX_Arena.cpp:899
std::size_t aligned_size(std::size_t align_requirement, std::size_t size) noexcept
Return the smallest multiple of align_requirement that is >= size.
Definition AMReX_Arena.H:39
__host__ __device__ T bisect(T lo, T hi, F f, T tol=1e-12, int max_iter=100)
Find a root of a scalar function on a bracketing interval using bisection.
Definition AMReX_Algorithm.H:170
void freeAsync(Arena *arena, void *mem) noexcept
Definition AMReX_GpuDevice.H:364
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:329
bool inNoSyncRegion() noexcept
Definition AMReX_GpuControl.H:148
gpuStream_t gpuStream() noexcept
Definition AMReX_GpuDevice.H:310
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int global_to_local_rank(int rank) noexcept
Definition AMReX_ParallelContext.H:101
Message Asend(const T *, size_t n, int pid, int tag)
Definition AMReX_ParallelDescriptor.H:1163
void Waitsome(Vector< MPI_Request > &, int &, Vector< int > &, Vector< MPI_Status > &)
Definition AMReX_ParallelDescriptor.cpp:1320
void Waitall(Vector< MPI_Request > &, Vector< MPI_Status > &)
Definition AMReX_ParallelDescriptor.cpp:1312
int SeqNum() noexcept
Returns sequential message sequence numbers, usually used as tags for send/recv.
Definition AMReX_ParallelDescriptor.H:678
Message Arecv(T *, size_t n, int pid, int tag)
Definition AMReX_ParallelDescriptor.H:1205
int MPI_Comm
Definition AMReX_ccse-mpi.H:51
static constexpr int MPI_REQUEST_NULL
Definition AMReX_ccse-mpi.H:57
Definition AMReX_Amr.cpp:50
@ F
Definition AMReX_Order.H:7
__host__ __device__ Dim3 begin(BoxND< dim > const &box) noexcept
Return the iterator begin coordinate of box as Dim3.
Definition AMReX_Box.H:2241
void launch(T const &n, L const &f) noexcept
Definition AMReX_GpuLaunchFunctsC.H:122
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:244
const int[]
Definition AMReX_BLProfiler.cpp:1665
__host__ __device__ Dim3 end(BoxND< dim > const &box) noexcept
Return the iterator end coordinate of box as Dim3.
Definition AMReX_Box.H:2259
Definition AMReX_TagParallelFor.H:106
Definition AMReX_TagParallelFor.H:116