LCOV - code coverage report
Current view: top level - ext/amrex/3d-coverage-g++-24.08/include - AMReX_FabArrayCommI.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 34 243 14.0 %
Date: 2024-11-18 05:28:54 Functions: 25 202 12.4 %

          Line data    Source code
       1             : 
       2             : #include <AMReX_FBI.H>
       3             : #include <AMReX_PCI.H>
       4             : 
       5             : template <class FAB>
       6             : template <typename BUF, class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
       7             : void
       8      275010 : FabArray<FAB>::FBEP_nowait (int scomp, int ncomp, const IntVect& nghost,
       9             :                             const Periodicity& period, bool cross,
      10             :                             bool enforce_periodicity_only,
      11             :                             bool override_sync)
      12             : {
      13             :     BL_PROFILE_SYNC_START_TIMED("SyncBeforeComms: FB");
      14             :     BL_PROFILE("FillBoundary_nowait()");
      15             : 
      16             :     AMREX_ASSERT_WITH_MESSAGE(!fbd, "FillBoundary_nowait() called when comm operation already in progress.");
      17             :     AMREX_ASSERT(!enforce_periodicity_only || !override_sync);
      18             : 
      19             :     bool work_to_do;
      20      275010 :     if (enforce_periodicity_only) {
      21           0 :         work_to_do = period.isAnyPeriodic();
      22      275010 :     } else if (override_sync) {
      23       33398 :         work_to_do = (nghost.max() > 0) || !is_cell_centered();
      24             :     } else {
      25      241612 :         work_to_do = nghost.max() > 0;
      26             :     }
      27      550020 :     if (!work_to_do) { return; }
      28             : 
      29      275010 :     const FB& TheFB = getFB(nghost, period, cross, enforce_periodicity_only, override_sync);
      30             : 
      31      275010 :     if (ParallelContext::NProcsSub() == 1)
      32             :     {
      33             :         //
      34             :         // There can only be local work to do.
      35             :         //
      36      275010 :         int N_locs = (*TheFB.m_LocTags).size();
      37      275010 :         if (N_locs == 0) { return; }
      38             : #ifdef AMREX_USE_GPU
      39             :         if (Gpu::inLaunchRegion())
      40             :         {
      41             : #if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
      42             :             if (Gpu::inGraphRegion())
      43             :             {
      44             :                 FB_local_copy_cuda_graph_1(TheFB, scomp, ncomp);
      45             :             }
      46             :             else
      47             : #endif
      48             :             {
      49             :                 FB_local_copy_gpu(TheFB, scomp, ncomp);
      50             :             }
      51             :         }
      52             :         else
      53             : #endif
      54             :         {
      55         132 :             FB_local_copy_cpu(TheFB, scomp, ncomp);
      56             :         }
      57             : 
      58         132 :         return;
      59             :     }
      60             : 
      61             : #ifdef BL_USE_MPI
      62             : 
      63             :     //
      64             :     // Do this before prematurely exiting if running in parallel.
      65             :     // Otherwise sequence numbers will not match across MPI processes.
      66             :     //
      67           0 :     int SeqNum = ParallelDescriptor::SeqNum();
      68             : 
      69           0 :     const int N_locs = TheFB.m_LocTags->size();
      70           0 :     const int N_rcvs = TheFB.m_RcvTags->size();
      71           0 :     const int N_snds = TheFB.m_SndTags->size();
      72             : 
      73           0 :     if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) {
      74             :         // No work to do.
      75           0 :         return;
      76             :     }
      77             : 
      78           0 :     fbd = std::make_unique<FBData<FAB>>();
      79           0 :     fbd->fb    = &TheFB;
      80           0 :     fbd->scomp = scomp;
      81           0 :     fbd->ncomp = ncomp;
      82           0 :     fbd->tag   = SeqNum;
      83             : 
      84             :     //
      85             :     // Post rcvs. Allocate one chunk of space to hold'm all.
      86             :     //
      87             : 
      88           0 :     if (N_rcvs > 0) {
      89           0 :         PostRcvs<BUF>(*TheFB.m_RcvTags, fbd->the_recv_data,
      90           0 :                       fbd->recv_data, fbd->recv_size, fbd->recv_from, fbd->recv_reqs,
      91             :                       ncomp, SeqNum);
      92           0 :         fbd->recv_stat.resize(N_rcvs);
      93             :     }
      94             : 
      95             :     //
      96             :     // Post send's
      97             :     //
      98           0 :     char*&                          the_send_data = fbd->the_send_data;
      99           0 :     Vector<char*> &                     send_data = fbd->send_data;
     100           0 :     Vector<std::size_t>                 send_size;
     101           0 :     Vector<int>                         send_rank;
     102           0 :     Vector<MPI_Request>&                send_reqs = fbd->send_reqs;
     103           0 :     Vector<const CopyComTagsContainer*> send_cctc;
     104             : 
     105           0 :     if (N_snds > 0)
     106             :     {
     107           0 :         PrepareSendBuffers<BUF>(*TheFB.m_SndTags, the_send_data, send_data, send_size, send_rank,
     108             :                            send_reqs, send_cctc, ncomp);
     109             : 
     110             : #ifdef AMREX_USE_GPU
     111             :         if (Gpu::inLaunchRegion())
     112             :         {
     113             : #if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
     114             :             if (Gpu::inGraphRegion()) {
     115             :                 FB_pack_send_buffer_cuda_graph(TheFB, scomp, ncomp, send_data, send_size, send_cctc);
     116             :             }
     117             :             else
     118             : #endif
     119             :             {
     120             :                 pack_send_buffer_gpu<BUF>(*this, scomp, ncomp, send_data, send_size, send_cctc);
     121             :             }
     122             :         }
     123             :         else
     124             : #endif
     125             :         {
     126           0 :             pack_send_buffer_cpu<BUF>(*this, scomp, ncomp, send_data, send_size, send_cctc);
     127             :         }
     128             : 
     129             :         AMREX_ASSERT(send_reqs.size() == N_snds);
     130           0 :         PostSnds(send_data, send_size, send_rank, send_reqs, SeqNum);
     131             :     }
     132             : 
     133           0 :     FillBoundary_test();
     134             : 
     135             :     //
     136             :     // Do the local work.  Hope for a bit of communication/computation overlap.
     137             :     //
     138           0 :     if (N_locs > 0)
     139             :     {
     140             : #ifdef AMREX_USE_GPU
     141             :         if (Gpu::inLaunchRegion())
     142             :         {
     143             : #if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
     144             :             if (Gpu::inGraphRegion()) {
     145             :                 FB_local_copy_cuda_graph_n(TheFB, scomp, ncomp);
     146             :             }
     147             :             else
     148             : #endif
     149             :             {
     150             :                 FB_local_copy_gpu(TheFB, scomp, ncomp);
     151             :             }
     152             :         }
     153             :         else
     154             : #endif
     155             :         {
     156           0 :             FB_local_copy_cpu(TheFB, scomp, ncomp);
     157             :         }
     158             : 
     159           0 :         FillBoundary_test();
     160             :     }
     161             : 
     162             : #endif /*BL_USE_MPI*/
     163             : }
     164             : 
     165             : template <class FAB>
     166             : template <typename BUF, class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
     167             : void
     168      275010 : FabArray<FAB>::FillBoundary_finish ()
     169             : {
     170             : #ifdef AMREX_USE_MPI
     171             : 
     172             :     BL_PROFILE("FillBoundary_finish()");
     173             :     BL_PROFILE_SYNC_STOP();
     174             : 
     175      550020 :     if (!fbd) { n_filled = IntVect::TheZeroVector(); return; }
     176             : 
     177           0 :     const FB* TheFB = fbd->fb;
     178           0 :     const auto N_rcvs = static_cast<int>(TheFB->m_RcvTags->size());
     179           0 :     if (N_rcvs > 0)
     180             :     {
     181           0 :         Vector<const CopyComTagsContainer*> recv_cctc(N_rcvs,nullptr);
     182           0 :         for (int k = 0; k < N_rcvs; k++)
     183             :         {
     184           0 :             if (fbd->recv_size[k] > 0)
     185             :             {
     186           0 :                 auto const& cctc = TheFB->m_RcvTags->at(fbd->recv_from[k]);
     187           0 :                 recv_cctc[k] = &cctc;
     188             :             }
     189             :         }
     190             : 
     191           0 :         int actual_n_rcvs = N_rcvs - std::count(fbd->recv_data.begin(), fbd->recv_data.end(), nullptr);
     192             : 
     193           0 :         if (actual_n_rcvs > 0) {
     194           0 :             ParallelDescriptor::Waitall(fbd->recv_reqs, fbd->recv_stat);
     195             : #ifdef AMREX_DEBUG
     196             :             if (!CheckRcvStats(fbd->recv_stat, fbd->recv_size, fbd->tag))
     197             :             {
     198             :                 amrex::Abort("FillBoundary_finish failed with wrong message size");
     199             :             }
     200             : #endif
     201             :         }
     202             : 
     203           0 :         bool is_thread_safe = TheFB->m_threadsafe_rcv;
     204             : 
     205             : #ifdef AMREX_USE_GPU
     206             :         if (Gpu::inLaunchRegion())
     207             :         {
     208             : #if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
     209             :             if (Gpu::inGraphRegion())
     210             :             {
     211             :                 FB_unpack_recv_buffer_cuda_graph(*TheFB, fbd->scomp, fbd->ncomp,
     212             :                                                  fbd->recv_data, fbd->recv_size,
     213             :                                                  recv_cctc, is_thread_safe);
     214             :             }
     215             :             else
     216             : #endif
     217             :             {
     218             :                 unpack_recv_buffer_gpu<BUF>(*this, fbd->scomp, fbd->ncomp, fbd->recv_data, fbd->recv_size,
     219             :                                             recv_cctc, FabArrayBase::COPY, is_thread_safe);
     220             :             }
     221             :         }
     222             :         else
     223             : #endif
     224             :         {
     225           0 :             unpack_recv_buffer_cpu<BUF>(*this, fbd->scomp, fbd->ncomp, fbd->recv_data, fbd->recv_size,
     226             :                                         recv_cctc, FabArrayBase::COPY, is_thread_safe);
     227             :         }
     228             : 
     229           0 :         if (fbd->the_recv_data)
     230             :         {
     231           0 :             amrex::The_Comms_Arena()->free(fbd->the_recv_data);
     232           0 :             fbd->the_recv_data = nullptr;
     233             :         }
     234             :     }
     235             : 
     236           0 :     const auto N_snds = static_cast<int>(TheFB->m_SndTags->size());
     237           0 :     if (N_snds > 0) {
     238           0 :         Vector<MPI_Status> stats(fbd->send_reqs.size());
     239           0 :         ParallelDescriptor::Waitall(fbd->send_reqs, stats);
     240           0 :         amrex::The_Comms_Arena()->free(fbd->the_send_data);
     241           0 :         fbd->the_send_data = nullptr;
     242             :     }
     243             : 
     244           0 :     fbd.reset();
     245             : 
     246             : #endif
     247             : }
     248             : 
     249             : // \cond CODEGEN
     250             : template <class FAB>
     251             : void
     252        6476 : FabArray<FAB>::ParallelCopy (const FabArray<FAB>& src,
     253             :                              int                  scomp,
     254             :                              int                  dcomp,
     255             :                              int                  ncomp,
     256             :                              const IntVect&       snghost,
     257             :                              const IntVect&       dnghost,
     258             :                              const Periodicity&   period,
     259             :                              CpOp                 op,
     260             :                              const FabArrayBase::CPC * a_cpc)
     261             : {
     262             :     BL_PROFILE("FabArray::ParallelCopy()");
     263             : 
     264        6476 :     ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period, op, a_cpc);
     265        6476 :     ParallelCopy_finish();
     266        6476 : }
     267             : 
     268             : template <class FAB>
     269             : void
     270           0 : FabArray<FAB>::ParallelCopyToGhost (const FabArray<FAB>& src,
     271             :                                     int                  scomp,
     272             :                                     int                  dcomp,
     273             :                                     int                  ncomp,
     274             :                                     const IntVect&       snghost,
     275             :                                     const IntVect&       dnghost,
     276             :                                     const Periodicity&   period)
     277             : {
     278             :     BL_PROFILE("FabArray::ParallelCopyToGhost()");
     279             : 
     280           0 :     ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period,
     281             :                         FabArrayBase::COPY, nullptr, true);
     282           0 :     ParallelCopy_finish();
     283           0 : }
     284             : 
     285             : template <class FAB>
     286             : void
     287             : FabArray<FAB>::ParallelCopyToGhost_nowait (const FabArray<FAB>& src,
     288             :                                            int                  scomp,
     289             :                                            int                  dcomp,
     290             :                                            int                  ncomp,
     291             :                                            const IntVect&       snghost,
     292             :                                            const IntVect&       dnghost,
     293             :                                            const Periodicity&   period)
     294             : {
     295             :     ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period,
     296             :                         FabArrayBase::COPY, nullptr, true);
     297             : }
     298             : 
     299             : template <class FAB>
     300             : void
     301             : FabArray<FAB>::ParallelCopyToGhost_finish ()
     302             : {
     303             :     ParallelCopy_finish();
     304             : }
     305             : 
     306             : 
     307             : template <class FAB>
     308             : void
     309        6476 : FabArray<FAB>::ParallelCopy_nowait (const FabArray<FAB>& src,
     310             :                                     int                  scomp,
     311             :                                     int                  dcomp,
     312             :                                     int                  ncomp,
     313             :                                     const IntVect&       snghost,
     314             :                                     const IntVect&       dnghost,
     315             :                                     const Periodicity&   period,
     316             :                                     CpOp                 op,
     317             :                                     const FabArrayBase::CPC * a_cpc,
     318             :                                     bool                 to_ghost_cells_only)
     319             : {
     320             :     BL_PROFILE_SYNC_START_TIMED("SyncBeforeComms: PC");
     321             :     BL_PROFILE("FabArray::ParallelCopy_nowait()");
     322             : 
     323             :     AMREX_ASSERT_WITH_MESSAGE(!pcd, "ParallelCopy_nowait() called when comm operation already in progress.");
     324             : 
     325        6476 :     if (empty() || src.empty()) {
     326        6476 :         return;
     327             :     }
     328             : 
     329             :     BL_ASSERT(op == FabArrayBase::COPY || op == FabArrayBase::ADD);
     330             :     BL_ASSERT(boxArray().ixType() == src.boxArray().ixType());
     331             :     BL_ASSERT(src.nGrowVect().allGE(snghost));
     332             :     BL_ASSERT(    nGrowVect().allGE(dnghost));
     333             : 
     334        6476 :     n_filled = dnghost;
     335             : 
     336       16852 :     if ((src.boxArray().ixType().cellCentered() || op == FabArrayBase::COPY) &&
     337       12776 :         (boxarray == src.boxarray && distributionMap == src.distributionMap) &&
     338       12600 :         snghost == IntVect::TheZeroVector() &&
     339           0 :         dnghost == IntVect::TheZeroVector() &&
     340       12952 :         !period.isAnyPeriodic() && !to_ghost_cells_only)
     341             :     {
     342             :         //
     343             :         // Short-circuit full intersection code if we're doing copy()s or if
     344             :         // we're doing plus()s on cell-centered data.  Don't do plus()s on
     345             :         // non-cell-centered data this simplistic way.
     346             :         //
     347           0 :         if (this != &src) { // avoid self copy or plus
     348           0 :             if (op == FabArrayBase::COPY) {
     349           0 :                 Copy(*this, src, scomp, dcomp, ncomp, IntVect(0));
     350             :             } else {
     351           0 :                 Add(*this, src, scomp, dcomp, ncomp, IntVect(0));
     352             :             }
     353             :         }
     354           0 :         return;
     355             :     }
     356             : 
     357        6476 :     const CPC& thecpc = (a_cpc) ? *a_cpc : getCPC(dnghost, src, snghost, period, to_ghost_cells_only);
     358             : 
     359        6476 :     if (ParallelContext::NProcsSub() == 1)
     360             :     {
     361             :         //
     362             :         // There can only be local work to do.
     363             :         //
     364             : 
     365        6476 :         int N_locs = (*thecpc.m_LocTags).size();
     366        6476 :         if (N_locs == 0) { return; }
     367             : #ifdef AMREX_USE_GPU
     368             :         if (Gpu::inLaunchRegion())
     369             :         {
     370             :             PC_local_gpu(thecpc, src, scomp, dcomp, ncomp, op);
     371             :         }
     372             :         else
     373             : #endif
     374             :         {
     375        6476 :             PC_local_cpu(thecpc, src, scomp, dcomp, ncomp, op);
     376             :         }
     377             : 
     378        6476 :         return;
     379             :     }
     380             : 
     381             : #ifdef BL_USE_MPI
     382             : 
     383             :     //
     384             :     // Do this before prematurely exiting if running in parallel.
     385             :     // Otherwise sequence numbers will not match across MPI processes.
     386             :     //
     387           0 :     int tag = ParallelDescriptor::SeqNum();
     388             : 
     389           0 :     const int N_snds = thecpc.m_SndTags->size();
     390           0 :     const int N_rcvs = thecpc.m_RcvTags->size();
     391           0 :     const int N_locs = thecpc.m_LocTags->size();
     392             : 
     393           0 :     if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) {
     394             :         //
     395             :         // No work to do.
     396             :         //
     397             : 
     398           0 :         return;
     399             :     }
     400             : 
     401             :     //
     402             :     // Send/Recv at most MaxComp components at a time to cut down memory usage.
     403             :     //
     404           0 :     int NCompLeft = ncomp;
     405           0 :     int SC = scomp, DC = dcomp, NC;
     406             : 
     407           0 :     for (int ipass = 0; ipass < ncomp; )
     408             :     {
     409           0 :         pcd = std::make_unique<PCData<FAB>>();
     410           0 :         pcd->cpc = &thecpc;
     411           0 :         pcd->src = &src;
     412           0 :         pcd->op = op;
     413           0 :         pcd->tag = tag;
     414             : 
     415           0 :         NC = std::min(NCompLeft,FabArrayBase::MaxComp);
     416           0 :         const bool last_iter = (NCompLeft == NC);
     417             : 
     418           0 :         pcd->SC = SC;
     419           0 :         pcd->DC = DC;
     420           0 :         pcd->NC = NC;
     421             : 
     422             :         //
     423             :         // Post rcvs. Allocate one chunk of space to hold'm all.
     424             :         //
     425           0 :         pcd->the_recv_data = nullptr;
     426             : 
     427           0 :         pcd->actual_n_rcvs = 0;
     428           0 :         if (N_rcvs > 0) {
     429           0 :             PostRcvs(*thecpc.m_RcvTags, pcd->the_recv_data,
     430           0 :                      pcd->recv_data, pcd->recv_size, pcd->recv_from, pcd->recv_reqs, NC, pcd->tag);
     431           0 :             pcd->actual_n_rcvs = N_rcvs - std::count(pcd->recv_size.begin(), pcd->recv_size.end(), 0);
     432             :         }
     433             : 
     434             :         //
     435             :         // Post send's
     436             :         //
     437           0 :         Vector<char*>                       send_data;
     438           0 :         Vector<std::size_t>                 send_size;
     439           0 :         Vector<int>                         send_rank;
     440           0 :         Vector<const CopyComTagsContainer*> send_cctc;
     441             : 
     442           0 :         if (N_snds > 0)
     443             :         {
     444           0 :             src.PrepareSendBuffers(*thecpc.m_SndTags, pcd->the_send_data, send_data, send_size,
     445           0 :                                    send_rank, pcd->send_reqs, send_cctc, NC);
     446             : 
     447             : #ifdef AMREX_USE_GPU
     448             :             if (Gpu::inLaunchRegion())
     449             :             {
     450             :                 pack_send_buffer_gpu(src, SC, NC, send_data, send_size, send_cctc);
     451             :             }
     452             :             else
     453             : #endif
     454             :             {
     455           0 :                 pack_send_buffer_cpu(src, SC, NC, send_data, send_size, send_cctc);
     456             :             }
     457             : 
     458             :             AMREX_ASSERT(pcd->send_reqs.size() == N_snds);
     459           0 :             FabArray<FAB>::PostSnds(send_data, send_size, send_rank, pcd->send_reqs, pcd->tag);
     460             :         }
     461             : 
     462             :         //
     463             :         // Do the local work.  Hope for a bit of communication/computation overlap.
     464             :         //
     465           0 :         if (N_locs > 0)
     466             :         {
     467             : #ifdef AMREX_USE_GPU
     468             :             if (Gpu::inLaunchRegion())
     469             :             {
     470             :                 PC_local_gpu(thecpc, src, SC, DC, NC, op);
     471             :             }
     472             :             else
     473             : #endif
     474             :             {
     475           0 :                 PC_local_cpu(thecpc, src, SC, DC, NC, op);
     476             :             }
     477             :         }
     478             : 
     479           0 :         if (!last_iter)
     480             :         {
     481           0 :             ParallelCopy_finish();
     482             : 
     483           0 :             SC += NC;
     484           0 :             DC += NC;
     485             :         }
     486             : 
     487           0 :         ipass     += NC;
     488           0 :         NCompLeft -= NC;
     489             :     }
     490             : 
     491             : #endif /*BL_USE_MPI*/
     492             : }
     493             : 
     494             : template <class FAB>
     495             : void
     496        6476 : FabArray<FAB>::ParallelCopy_finish ()
     497             : {
     498             : 
     499             : #ifdef BL_USE_MPI
     500             : 
     501             :     BL_PROFILE("FabArray::ParallelCopy_finish()");
     502             :     BL_PROFILE_SYNC_STOP();
     503             : 
     504        6476 :     if (!pcd) { return; }
     505             : 
     506           0 :     const CPC* thecpc = pcd->cpc;
     507             : 
     508           0 :     const auto N_snds = static_cast<int>(thecpc->m_SndTags->size());
     509           0 :     const auto N_rcvs = static_cast<int>(thecpc->m_RcvTags->size());
     510             : 
     511           0 :     if (N_rcvs > 0)
     512             :     {
     513           0 :         Vector<const CopyComTagsContainer*> recv_cctc(N_rcvs,nullptr);
     514           0 :         for (int k = 0; k < N_rcvs; ++k)
     515             :         {
     516           0 :             if (pcd->recv_size[k] > 0)
     517             :             {
     518           0 :                 auto const& cctc = thecpc->m_RcvTags->at(pcd->recv_from[k]);
     519           0 :                 recv_cctc[k] = &cctc;
     520             :             }
     521             :         }
     522             : 
     523           0 :         if (pcd->actual_n_rcvs > 0) {
     524           0 :             Vector<MPI_Status> stats(N_rcvs);
     525           0 :             ParallelDescriptor::Waitall(pcd->recv_reqs, stats);
     526             : #ifdef AMREX_DEBUG
     527             :             if (!CheckRcvStats(stats, pcd->recv_size, pcd->tag))
     528             :             {
     529             :                 amrex::Abort("ParallelCopy failed with wrong message size");
     530             :             }
     531             : #endif
     532             :         }
     533             : 
     534           0 :         bool is_thread_safe = thecpc->m_threadsafe_rcv;
     535             : 
     536             : #ifdef AMREX_USE_GPU
     537             :         if (Gpu::inLaunchRegion())
     538             :         {
     539             :             unpack_recv_buffer_gpu(*this, pcd->DC, pcd->NC, pcd->recv_data, pcd->recv_size,
     540             :                                    recv_cctc, pcd->op, is_thread_safe);
     541             :         }
     542             :         else
     543             : #endif
     544             :         {
     545           0 :             unpack_recv_buffer_cpu(*this, pcd->DC, pcd->NC, pcd->recv_data, pcd->recv_size,
     546           0 :                                    recv_cctc, pcd->op, is_thread_safe);
     547             :         }
     548             : 
     549           0 :         if (pcd->the_recv_data)
     550             :         {
     551           0 :             amrex::The_Comms_Arena()->free(pcd->the_recv_data);
     552           0 :             pcd->the_recv_data = nullptr;
     553             :         }
     554             :     }
     555             : 
     556           0 :     if (N_snds > 0) {
     557           0 :         if (! thecpc->m_SndTags->empty()) {
     558           0 :             Vector<MPI_Status> stats(pcd->send_reqs.size());
     559           0 :             ParallelDescriptor::Waitall(pcd->send_reqs, stats);
     560             :         }
     561           0 :         amrex::The_Comms_Arena()->free(pcd->the_send_data);
     562           0 :         pcd->the_send_data = nullptr;
     563             :     }
     564             : 
     565           0 :     pcd.reset();
     566             : 
     567             : #endif /*BL_USE_MPI*/
     568             : }
     569             : 
     570             : template <class FAB>
     571             : void
     572             : FabArray<FAB>::copyTo (FAB& dest, int scomp, int dcomp, int ncomp, int nghost) const
     573             : {
     574             :     BL_PROFILE("FabArray::copy(fab)");
     575             : 
     576             :     BL_ASSERT(dcomp + ncomp <= dest.nComp());
     577             :     BL_ASSERT(IntVect(nghost).allLE(nGrowVect()));
     578             : 
     579             :     int root_proc = this->DistributionMap()[0];
     580             : 
     581             :     BoxArray ba(dest.box());
     582             :     DistributionMapping dm(Vector<int>{root_proc});
     583             :     FabArray<FAB> destmf(ba, dm, ncomp, 0, MFInfo().SetAlloc(false));
     584             :     if (ParallelDescriptor::MyProc() == root_proc) {
     585             :         destmf.setFab(0, FAB(dest, amrex::make_alias, dcomp, ncomp));
     586             :     }
     587             : 
     588             :     destmf.ParallelCopy(*this, scomp, 0, ncomp, nghost, 0);
     589             : 
     590             : #ifdef BL_USE_MPI
     591             :     using T = typename FAB::value_type;
     592             :     if (ParallelContext::NProcsSub() > 1) {
     593             :         Long count = dest.numPts()*ncomp;
     594             :         T* const p0 = dest.dataPtr(dcomp);
     595             :         T* pb = p0;
     596             : #ifdef AMREX_USE_GPU
     597             :         if (dest.arena()->isDevice()) {
     598             :             pb = (T*)The_Pinned_Arena()->alloc(sizeof(T)*count);
     599             :             Gpu::dtoh_memcpy_async(pb, p0, sizeof(T)*count);
     600             :             Gpu::streamSynchronize();
     601             :         }
     602             : #endif
     603             :         ParallelDescriptor::Bcast(pb, count, ParallelContext::global_to_local_rank(root_proc),
     604             :                                   ParallelContext::CommunicatorSub());
     605             : #ifdef AMREX_USE_GPU
     606             :         if (pb != p0) {
     607             :             Gpu::htod_memcpy_async(p0, pb, sizeof(T)*count);
     608             :             Gpu::streamSynchronize();
     609             :         }
     610             : #endif
     611             :     }
     612             : #endif
     613             : }
     614             : // \endcond
     615             : #ifdef BL_USE_MPI
     616             : template <class FAB>
     617             : template <typename BUF>
     618             : AMREX_NODISCARD TheFaArenaPointer
     619             : FabArray<FAB>::PrepareSendBuffers (const MapOfCopyComTagContainers&     SndTags,
     620             :                                    Vector<char*>&                       send_data,
     621             :                                    Vector<std::size_t>&                 send_size,
     622             :                                    Vector<int>&                         send_rank,
     623             :                                    Vector<MPI_Request>&                 send_reqs,
     624             :                                    Vector<const CopyComTagsContainer*>& send_cctc,
     625             :                                    int                                  ncomp)
     626             : {
     627             :     char* pointer = nullptr;
     628             :     PrepareSendBuffers<BUF>(SndTags, pointer, send_data, send_size, send_rank, send_reqs, send_cctc, ncomp);
     629             :     return TheFaArenaPointer(pointer);
     630             : }
     631             : 
     632             : template <class FAB>
     633             : template <typename BUF>
     634             : void
     635           0 : FabArray<FAB>::PrepareSendBuffers (const MapOfCopyComTagContainers&     SndTags,
     636             :                                    char*&                               the_send_data,
     637             :                                    Vector<char*>&                       send_data,
     638             :                                    Vector<std::size_t>&                 send_size,
     639             :                                    Vector<int>&                         send_rank,
     640             :                                    Vector<MPI_Request>&                 send_reqs,
     641             :                                    Vector<const CopyComTagsContainer*>& send_cctc,
     642             :                                    int                                  ncomp)
     643             : {
     644           0 :     send_data.clear();
     645           0 :     send_size.clear();
     646           0 :     send_rank.clear();
     647           0 :     send_reqs.clear();
     648           0 :     send_cctc.clear();
     649           0 :     const auto N_snds = SndTags.size();
     650           0 :     if (N_snds == 0) { return; }
     651           0 :     send_data.reserve(N_snds);
     652           0 :     send_size.reserve(N_snds);
     653           0 :     send_rank.reserve(N_snds);
     654           0 :     send_reqs.reserve(N_snds);
     655           0 :     send_cctc.reserve(N_snds);
     656             : 
     657           0 :     Vector<std::size_t> offset; offset.reserve(N_snds);
     658           0 :     std::size_t total_volume = 0;
     659           0 :     for (auto const& kv : SndTags)
     660             :     {
     661           0 :         auto const& cctc = kv.second;
     662             : 
     663           0 :         std::size_t nbytes = 0;
     664           0 :         for (auto const& cct : kv.second)
     665             :         {
     666           0 :             nbytes += cct.sbox.numPts() * ncomp * sizeof(BUF);
     667             :         }
     668             : 
     669           0 :         std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
     670           0 :         nbytes = amrex::aligned_size(acd, nbytes); // so that bytes are aligned
     671             : 
     672             :         // Also need to align the offset properly
     673           0 :         total_volume = amrex::aligned_size(std::max(alignof(BUF), acd),
     674             :                                            total_volume);
     675             : 
     676           0 :         offset.push_back(total_volume);
     677           0 :         total_volume += nbytes;
     678             : 
     679           0 :         send_data.push_back(nullptr);
     680           0 :         send_size.push_back(nbytes);
     681           0 :         send_rank.push_back(kv.first);
     682           0 :         send_reqs.push_back(MPI_REQUEST_NULL);
     683           0 :         send_cctc.push_back(&cctc);
     684             :     }
     685             : 
     686           0 :     if (total_volume > 0)
     687             :     {
     688           0 :         the_send_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(total_volume));
     689           0 :         for (int i = 0, N = static_cast<int>(send_size.size()); i < N; ++i) {
     690           0 :             send_data[i] = the_send_data + offset[i];
     691             :         }
     692             :     } else {
     693           0 :         the_send_data = nullptr;
     694             :     }
     695             : }
     696             : 
     697             : template <class FAB>
     698             : void
     699           0 : FabArray<FAB>::PostSnds (Vector<char*> const&       send_data,
     700             :                          Vector<std::size_t> const& send_size,
     701             :                          Vector<int> const&         send_rank,
     702             :                          Vector<MPI_Request>&       send_reqs,
     703             :                          int                        SeqNum)
     704             : {
     705           0 :     MPI_Comm comm = ParallelContext::CommunicatorSub();
     706             : 
     707           0 :     const auto N_snds = static_cast<int>(send_reqs.size());
     708           0 :     for (int j = 0; j < N_snds; ++j)
     709             :     {
     710           0 :         if (send_size[j] > 0) {
     711           0 :             const int rank = ParallelContext::global_to_local_rank(send_rank[j]);
     712           0 :             send_reqs[j] = ParallelDescriptor::Asend
     713           0 :                 (send_data[j], send_size[j], rank, SeqNum, comm).req();
     714             :         }
     715             :     }
     716           0 : }
     717             : 
     718             : template <class FAB>
     719             : template <typename BUF>
     720             : TheFaArenaPointer FabArray<FAB>::PostRcvs (const MapOfCopyComTagContainers&       RcvTags,
     721             :                    Vector<char*>&                         recv_data,
     722             :                    Vector<std::size_t>&                   recv_size,
     723             :                    Vector<int>&                           recv_from,
     724             :                    Vector<MPI_Request>&                   recv_reqs,
     725             :                    int                                    ncomp,
     726             :                    int                                    SeqNum)
     727             : {
     728             :     char* pointer = nullptr;
     729             :     PostRcvs(RcvTags, pointer, recv_data, recv_size, recv_from, recv_reqs, ncomp, SeqNum);
     730             :     return TheFaArenaPointer(pointer);
     731             : }
     732             : 
     733             : template <class FAB>
     734             : template <typename BUF>
     735             : void
     736           0 : FabArray<FAB>::PostRcvs (const MapOfCopyComTagContainers&  RcvTags,
     737             :                          char*&                            the_recv_data,
     738             :                          Vector<char*>&                    recv_data,
     739             :                          Vector<std::size_t>&              recv_size,
     740             :                          Vector<int>&                      recv_from,
     741             :                          Vector<MPI_Request>&              recv_reqs,
     742             :                          int                               ncomp,
     743             :                          int                               SeqNum)
     744             : {
     745           0 :     recv_data.clear();
     746           0 :     recv_size.clear();
     747           0 :     recv_from.clear();
     748           0 :     recv_reqs.clear();
     749             : 
     750           0 :     Vector<std::size_t> offset;
     751           0 :     std::size_t TotalRcvsVolume = 0;
     752           0 :     for (const auto& kv : RcvTags) // loop over senders
     753             :     {
     754           0 :         std::size_t nbytes = 0;
     755           0 :         for (auto const& cct : kv.second)
     756             :         {
     757           0 :             nbytes += cct.dbox.numPts() * ncomp * sizeof(BUF);
     758             :         }
     759             : 
     760           0 :         std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
     761           0 :         nbytes = amrex::aligned_size(acd, nbytes);  // so that nbytes are aligned
     762             : 
     763             :         // Also need to align the offset properly
     764           0 :         TotalRcvsVolume = amrex::aligned_size(std::max(alignof(BUF),acd),
     765             :                                               TotalRcvsVolume);
     766             : 
     767           0 :         offset.push_back(TotalRcvsVolume);
     768           0 :         TotalRcvsVolume += nbytes;
     769             : 
     770           0 :         recv_data.push_back(nullptr);
     771           0 :         recv_size.push_back(nbytes);
     772           0 :         recv_from.push_back(kv.first);
     773           0 :         recv_reqs.push_back(MPI_REQUEST_NULL);
     774             :     }
     775             : 
     776           0 :     const auto nrecv = static_cast<int>(recv_from.size());
     777             : 
     778           0 :     MPI_Comm comm = ParallelContext::CommunicatorSub();
     779             : 
     780           0 :     if (TotalRcvsVolume == 0)
     781             :     {
     782           0 :         the_recv_data = nullptr;
     783             :     }
     784             :     else
     785             :     {
     786           0 :         the_recv_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalRcvsVolume));
     787             : 
     788           0 :         for (int i = 0; i < nrecv; ++i)
     789             :         {
     790           0 :             recv_data[i] = the_recv_data + offset[i];
     791           0 :             if (recv_size[i] > 0)
     792             :             {
     793           0 :                 const int rank = ParallelContext::global_to_local_rank(recv_from[i]);
     794           0 :                 recv_reqs[i] = ParallelDescriptor::Arecv
     795           0 :                     (recv_data[i], recv_size[i], rank, SeqNum, comm).req();
     796             :             }
     797             :         }
     798             :     }
     799           0 : }
     800             : #endif
     801             : 
     802             : template <class FAB>
     803             : void
     804             : FabArray<FAB>::Redistribute (const FabArray<FAB>& src,
     805             :                              int                  scomp,
     806             :                              int                  dcomp,
     807             :                              int                  ncomp,
     808             :                              const IntVect&       nghost)
     809             : {
     810             :     AMREX_ALWAYS_ASSERT_WITH_MESSAGE(boxArray() == src.boxArray(),
     811             :                                      "FabArray::Redistribute: must have the same BoxArray");
     812             : 
     813             :     if (ParallelContext::NProcsSub() == 1)
     814             :     {
     815             :         Copy(*this, src, scomp, dcomp, ncomp, nghost);
     816             :         return;
     817             :     }
     818             : 
     819             : #ifdef BL_USE_MPI
     820             : 
     821             :     FabArrayBase::CPC cpc(boxArray(), nghost, DistributionMap(), src.DistributionMap());
     822             : 
     823             :     ParallelCopy(src, scomp, dcomp, ncomp, nghost, nghost, Periodicity::NonPeriodic(),
     824             :                  FabArrayBase::COPY, &cpc);
     825             : 
     826             : #endif
     827             : }
     828             : 
     829             : template <class FAB>
     830             : void
     831           0 : FabArray<FAB>::FillBoundary_test ()
     832             : {
     833             : #if defined(AMREX_USE_MPI) && !defined(AMREX_DEBUG)
     834             :     // We only test if no DEBUG because in DEBUG we check the status later.
     835             :     // If Test is done here, the status check will fail.
     836             :     int flag;
     837           0 :     ParallelDescriptor::Test(fbd->recv_reqs, flag, fbd->recv_stat);
     838             : #endif
     839           0 : }
     840             : 
     841             : namespace detail {
     842             : template <class TagT>
     843             : void fbv_copy (Vector<TagT> const& tags)
     844             : {
     845             :     const int N = tags.size();
     846             :     if (N == 0) { return; }
     847             : #ifdef AMREX_USE_GPU
     848             :     if (Gpu::inLaunchRegion()) {
     849             :         ParallelFor(tags, 1,
     850             :         [=] AMREX_GPU_DEVICE (int i, int j, int k, int, TagT const& tag) noexcept
     851             :         {
     852             :             const int ncomp = tag.dfab.nComp();
     853             :             for (int n = 0; n < ncomp; ++n) {
     854             :                 tag.dfab(i,j,k,n) = tag.sfab(i+tag.offset.x,j+tag.offset.y,k+tag.offset.z,n);
     855             :             }
     856             :         });
     857             :     } else
     858             : #endif
     859             :     {
     860             : #ifdef AMREX_USE_OMP
     861             : #pragma omp parallel for
     862             : #endif
     863             :         for (int itag = 0; itag < N; ++itag) {
     864             :             auto const& tag = tags[itag];
     865             :             const int ncomp = tag.dfab.nComp();
     866             :             AMREX_LOOP_4D(tag.dbox, ncomp, i, j, k, n,
     867             :             {
     868             :                 tag.dfab(i,j,k,n) = tag.sfab(i+tag.offset.x,j+tag.offset.y,k+tag.offset.z,n);
     869             :             });
     870             :         }
     871             :     }
     872             : }
     873             : }
     874             : 
     875             : template <class MF>
     876             : std::enable_if_t<IsFabArray<MF>::value>
     877             : FillBoundary (Vector<MF*> const& mf, Vector<int> const& scomp,
     878             :               Vector<int> const& ncomp, Vector<IntVect> const& nghost,
     879             :               Vector<Periodicity> const& period, Vector<int> const& cross = {})
     880             : {
     881             :     BL_PROFILE("FillBoundary(Vector)");
     882             : #if 1
     883             :     const int N = mf.size();
     884             :     for (int i = 0; i < N; ++i) {
     885             :         mf[i]->FillBoundary_nowait(scomp[i], ncomp[i], nghost[i], period[i],
     886             :                                    cross.empty() ? 0 : cross[i]);
     887             :     }
     888             :     for (int i = 0; i < N; ++i) {
     889             :         mf[i]->FillBoundary_finish();
     890             :     }
     891             : 
     892             : #else
     893             :     using FAB = typename MF::FABType::value_type;
     894             :     using T   = typename FAB::value_type;
     895             : 
     896             :     const int nmfs = mf.size();
     897             :     Vector<FabArrayBase::CommMetaData const*> cmds;
     898             :     int N_locs = 0;
     899             :     int N_rcvs = 0;
     900             :     int N_snds = 0;
     901             :     for (int imf = 0; imf < nmfs; ++imf) {
     902             :         if (nghost[imf].max() > 0) {
     903             :             auto const& TheFB = mf[imf]->getFB(nghost[imf], period[imf],
     904             :                                                cross.empty() ? 0 : cross[imf]);
     905             :             // The FB is cached.  Therefore it's safe take its address for later use.
     906             :             cmds.push_back(static_cast<FabArrayBase::CommMetaData const*>(&TheFB));
     907             :             N_locs += TheFB.m_LocTags->size();
     908             :             N_rcvs += TheFB.m_RcvTags->size();
     909             :             N_snds += TheFB.m_SndTags->size();
     910             :         } else {
     911             :             cmds.push_back(nullptr);
     912             :         }
     913             :     }
     914             : 
     915             :     using TagT = Array4CopyTag<T>;
     916             :     Vector<TagT> local_tags;
     917             :     local_tags.reserve(N_locs);
     918             :     static_assert(amrex::IsStoreAtomic<T>::value, "FillBoundary(Vector): storing T is not atomic");
     919             :     for (int imf = 0; imf < nmfs; ++imf) {
     920             :         if (cmds[imf]) {
     921             :             auto const& tags = *(cmds[imf]->m_LocTags);
     922             :             for (auto const& tag : tags) {
     923             :                 local_tags.push_back({(*mf[imf])[tag.dstIndex].array      (scomp[imf],ncomp[imf]),
     924             :                                       (*mf[imf])[tag.srcIndex].const_array(scomp[imf],ncomp[imf]),
     925             :                                       tag.dbox,
     926             :                                       (tag.sbox.smallEnd()-tag.dbox.smallEnd()).dim3()});
     927             :             }
     928             :         }
     929             :     }
     930             : 
     931             :     if (ParallelContext::NProcsSub() == 1) {
     932             :         detail::fbv_copy(local_tags);
     933             :         return;
     934             :     }
     935             : 
     936             : #ifdef AMREX_USE_MPI
     937             :     //
     938             :     // Do this before prematurely exiting if running in parallel.
     939             :     // Otherwise sequence numbers will not match across MPI processes.
     940             :     //
     941             :     int SeqNum = ParallelDescriptor::SeqNum();
     942             :     MPI_Comm comm = ParallelContext::CommunicatorSub();
     943             : 
     944             :     if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) { return; } // No work to do
     945             : 
     946             :     char* the_recv_data = nullptr;
     947             :     Vector<int> recv_from;
     948             :     Vector<std::size_t> recv_size;
     949             :     Vector<MPI_Request> recv_reqs;
     950             :     Vector<MPI_Status> recv_stat;
     951             :     Vector<TagT> recv_tags;
     952             : 
     953             :     if (N_rcvs > 0) {
     954             : 
     955             :         for (int imf = 0; imf < nmfs; ++imf) {
     956             :             if (cmds[imf]) {
     957             :                 auto const& tags = *(cmds[imf]->m_RcvTags);
     958             :                 for (const auto& kv : tags) {
     959             :                     recv_from.push_back(kv.first);
     960             :                 }
     961             :             }
     962             :         }
     963             :         amrex::RemoveDuplicates(recv_from);
     964             :         const int nrecv = recv_from.size();
     965             : 
     966             :         recv_reqs.resize(nrecv, MPI_REQUEST_NULL);
     967             :         recv_stat.resize(nrecv);
     968             : 
     969             :         recv_tags.reserve(N_rcvs);
     970             : 
     971             :         Vector<Vector<std::size_t> > recv_offset(nrecv);
     972             :         Vector<std::size_t> offset;
     973             :         recv_size.reserve(nrecv);
     974             :         offset.reserve(nrecv);
     975             :         std::size_t TotalRcvsVolume = 0;
     976             :         for (int i = 0; i < nrecv; ++i) {
     977             :             std::size_t nbytes = 0;
     978             :             for (int imf = 0; imf < nmfs; ++imf) {
     979             :                 if (cmds[imf]) {
     980             :                     auto const& tags = *(cmds[imf]->m_RcvTags);
     981             :                     auto it = tags.find(recv_from[i]);
     982             :                     if (it != tags.end()) {
     983             :                         for (auto const& cct : it->second) {
     984             :                             auto& dfab = (*mf[imf])[cct.dstIndex];
     985             :                             recv_offset[i].push_back(nbytes);
     986             :                             recv_tags.push_back({dfab.array(scomp[imf],ncomp[imf]),
     987             :                                                  makeArray4<T const>(nullptr,cct.dbox,ncomp[imf]),
     988             :                                                  cct.dbox, Dim3{0,0,0}});
     989             :                             nbytes += dfab.nBytes(cct.dbox,ncomp[imf]);
     990             :                         }
     991             :                     }
     992             :                 }
     993             :             }
     994             : 
     995             :             std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
     996             :             nbytes = amrex::aligned_size(acd, nbytes); // so that nbytes are aligned
     997             : 
     998             :             // Also need to align the offset properly
     999             :             TotalRcvsVolume = amrex::aligned_size(std::max(alignof(T),acd), TotalRcvsVolume);
    1000             : 
    1001             :             offset.push_back(TotalRcvsVolume);
    1002             :             TotalRcvsVolume += nbytes;
    1003             : 
    1004             :             recv_size.push_back(nbytes);
    1005             :         }
    1006             : 
    1007             :         the_recv_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalRcvsVolume));
    1008             : 
    1009             :         int k = 0;
    1010             :         for (int i = 0; i < nrecv; ++i) {
    1011             :             char* p = the_recv_data + offset[i];
    1012             :             const int rank = ParallelContext::global_to_local_rank(recv_from[i]);
    1013             :             recv_reqs[i] = ParallelDescriptor::Arecv
    1014             :                 (p, recv_size[i], rank, SeqNum, comm).req();
    1015             :             for (int j = 0, nj = recv_offset[i].size(); j < nj; ++j) {
    1016             :                 recv_tags[k++].sfab.p = (T const*)(p + recv_offset[i][j]);
    1017             :             }
    1018             :         }
    1019             :     }
    1020             : 
    1021             :     char* the_send_data = nullptr;
    1022             :     Vector<int> send_rank;
    1023             :     Vector<char*> send_data;
    1024             :     Vector<std::size_t> send_size;
    1025             :     Vector<MPI_Request> send_reqs;
    1026             :     if (N_snds > 0) {
    1027             :         for (int imf = 0; imf < nmfs; ++imf) {
    1028             :             if (cmds[imf]) {
    1029             :                 auto const& tags = *(cmds[imf]->m_SndTags);
    1030             :                 for (auto const& kv : tags) {
    1031             :                     send_rank.push_back(kv.first);
    1032             :                 }
    1033             :             }
    1034             :         }
    1035             :         amrex::RemoveDuplicates(send_rank);
    1036             :         const int nsend = send_rank.size();
    1037             : 
    1038             :         send_data.resize(nsend, nullptr);
    1039             :         send_reqs.resize(nsend, MPI_REQUEST_NULL);
    1040             : 
    1041             :         Vector<TagT> send_tags;
    1042             :         send_tags.reserve(N_snds);
    1043             : 
    1044             :         Vector<Vector<std::size_t> > send_offset(nsend);
    1045             :         Vector<std::size_t> offset;
    1046             :         send_size.reserve(nsend);
    1047             :         offset.reserve(nsend);
    1048             :         std::size_t TotalSndsVolume = 0;
    1049             :         for (int i = 0; i < nsend; ++i) {
    1050             :             std::size_t nbytes = 0;
    1051             :             for (int imf = 0; imf < nmfs; ++imf) {
    1052             :                 if (cmds[imf]) {
    1053             :                     auto const& tags = *(cmds[imf]->m_SndTags);
    1054             :                     auto it = tags.find(send_rank[i]);
    1055             :                     if (it != tags.end()) {
    1056             :                         for (auto const& cct : it->second) {
    1057             :                             auto const& sfab = (*mf[imf])[cct.srcIndex];
    1058             :                             send_offset[i].push_back(nbytes);
    1059             :                             send_tags.push_back({amrex::makeArray4<T>(nullptr,cct.sbox,ncomp[imf]),
    1060             :                                                  sfab.const_array(scomp[imf],ncomp[imf]),
    1061             :                                                  cct.sbox, Dim3{0,0,0}});
    1062             :                             nbytes += sfab.nBytes(cct.sbox,ncomp[imf]);
    1063             :                         }
    1064             :                     }
    1065             :                 }
    1066             :             }
    1067             : 
    1068             :             std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
    1069             :             nbytes = amrex::aligned_size(acd, nbytes); // so that bytes are aligned
    1070             : 
    1071             :             // Also need to align the offset properly
    1072             :             TotalSndsVolume = amrex::aligned_size(std::max(alignof(T),acd), TotalSndsVolume);
    1073             : 
    1074             :             offset.push_back(TotalSndsVolume);
    1075             :             TotalSndsVolume += nbytes;
    1076             : 
    1077             :             send_size.push_back(nbytes);
    1078             :         }
    1079             : 
    1080             :         the_send_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalSndsVolume));
    1081             :         int k = 0;
    1082             :         for (int i = 0; i < nsend; ++i) {
    1083             :             send_data[i] = the_send_data + offset[i];
    1084             :             for (int j = 0, nj = send_offset[i].size(); j < nj; ++j) {
    1085             :                 send_tags[k++].dfab.p = (T*)(send_data[i] + send_offset[i][j]);
    1086             :             }
    1087             :         }
    1088             : 
    1089             :         detail::fbv_copy(send_tags);
    1090             : 
    1091             :         FabArray<FAB>::PostSnds(send_data, send_size, send_rank, send_reqs, SeqNum);
    1092             :     }
    1093             : 
    1094             : #if !defined(AMREX_DEBUG)
    1095             :     int recv_flag;
    1096             :     ParallelDescriptor::Test(recv_reqs, recv_flag, recv_stat);
    1097             : #endif
    1098             : 
    1099             :     if (N_locs > 0) {
    1100             :         detail::fbv_copy(local_tags);
    1101             : #if !defined(AMREX_DEBUG)
    1102             :         ParallelDescriptor::Test(recv_reqs, recv_flag, recv_stat);
    1103             : #endif
    1104             :     }
    1105             : 
    1106             :     if (N_rcvs > 0) {
    1107             :         ParallelDescriptor::Waitall(recv_reqs, recv_stat);
    1108             : #ifdef AMREX_DEBUG
    1109             :         if (!FabArrayBase::CheckRcvStats(recv_stat, recv_size, SeqNum)) {
    1110             :             amrex::Abort("FillBoundary(vector) failed with wrong message size");
    1111             :         }
    1112             : #endif
    1113             : 
    1114             :         detail::fbv_copy(recv_tags);
    1115             : 
    1116             :         amrex::The_Comms_Arena()->free(the_recv_data);
    1117             :     }
    1118             : 
    1119             :     if (N_snds > 0) {
    1120             :         Vector<MPI_Status> stats(send_reqs.size());
    1121             :         ParallelDescriptor::Waitall(send_reqs, stats);
    1122             :         amrex::The_Comms_Arena()->free(the_send_data);
    1123             :     }
    1124             : 
    1125             : #endif  // #ifdef AMREX_USE_MPI
    1126             : #endif  // #if 1 #else
    1127             : }
    1128             : 
    1129             : template <class MF>
    1130             : std::enable_if_t<IsFabArray<MF>::value>
    1131             : FillBoundary (Vector<MF*> const& mf, const Periodicity& a_period = Periodicity::NonPeriodic())
    1132             : {
    1133             :     Vector<int> scomp(mf.size(), 0);
    1134             :     Vector<int> ncomp;
    1135             :     Vector<IntVect> nghost;
    1136             :     Vector<Periodicity> period(mf.size(), a_period);
    1137             :     ncomp.reserve(mf.size());
    1138             :     nghost.reserve(mf.size());
    1139             :     for (auto const& x : mf) {
    1140             :         ncomp.push_back(x->nComp());
    1141             :         nghost.push_back(x->nGrowVect());
    1142             :     }
    1143             :     FillBoundary(mf, scomp, ncomp, nghost, period);
    1144             : }

Generated by: LCOV version 1.14