41 use mpi_f08,
only : mpi_win, mpi_info, mpi_win_allocate, mpi_win_free, &
42 mpi_win_lock_all, mpi_win_unlock_all, mpi_win_flush, &
44 mpi_win_sync, mpi_win_get_attr, mpi_put, mpi_accumulate, &
45 mpi_alltoall, mpi_barrier, mpi_iprobe, mpi_status, &
46 mpi_info_create, mpi_info_set, mpi_info_free, &
47 mpi_integer, mpi_integer8, mpi_replace, mpi_mode_nocheck, &
48 mpi_address_kind, mpi_win_model, mpi_win_unified, &
49 mpi_any_source, mpi_any_tag
50 use,
intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr, c_f_pointer, &
51 c_associated, c_sizeof
75 real(kind=
rp),
allocatable :: send_buf(:)
77 integer,
allocatable :: send_ndofs(:)
79 integer,
allocatable :: send_offset(:)
82 integer,
allocatable :: send_rdisp(:)
85 type(mpi_win) :: win_data
87 type(c_ptr) :: recv_ptr = c_null_ptr
89 integer,
allocatable :: recv_ndofs(:)
91 integer,
allocatable :: recv_offset(:)
93 integer :: recv_total = 0
96 type(mpi_win) :: win_sig
98 type(c_ptr) :: sig_ptr = c_null_ptr
103 integer(kind=i8) :: iter = 0
108 logical :: unified = .true.
112 logical :: win_alloc = .false.
131 type(mpi_info) :: info
132 integer(kind=MPI_ADDRESS_KIND) :: win_size, attr_val
133 integer,
allocatable :: local_disp(:), remote_disp(:)
134 integer(kind=i8),
pointer :: sig(:)
135 integer :: i, n, send_total, ierr, disp_unit, env_len
136 integer(kind=i8) :: i8_dummy
137 real(kind=
rp) :: rp_dummy
138 character(len=255) :: env_val
144 call this%init_order(send_pe, recv_pe)
149 call get_environment_variable(
"NEKO_GS_RMA_FLUSH_ALL", env_val, env_len)
150 if (env_len .gt. 0)
then
151 env_len = min(env_len, len(env_val))
158 n =
size(this%send_pe)
159 allocate(this%send_ndofs(n), this%send_offset(n), this%send_rdisp(n))
162 this%send_ndofs(i) = this%send_dof(this%send_pe(i))%size()
163 this%send_offset(i) = send_total
164 send_total = send_total + this%send_ndofs(i)
170 n =
size(this%recv_pe)
171 allocate(this%recv_ndofs(n), this%recv_offset(n))
174 this%recv_ndofs(i) = this%recv_dof(this%recv_pe(i))%size()
175 this%recv_offset(i) = this%recv_total
176 this%recv_total = this%recv_total + this%recv_ndofs(i)
191 call mpi_info_create(info, ierr)
192 call mpi_info_set(info,
'same_disp_unit',
'true', ierr)
193 call mpi_info_set(info,
'accumulate_ordering',
'none', ierr)
194 call mpi_info_set(info,
'accumulate_ops',
'same_op', ierr)
196 disp_unit = int(c_sizeof(rp_dummy))
197 win_size = int(
max(
gs_vec_nc*this%recv_total, 1), mpi_address_kind) * &
198 int(disp_unit, mpi_address_kind)
199 call mpi_win_allocate(win_size, disp_unit, info,
neko_comm, &
200 this%recv_ptr, this%win_data, ierr)
201 if (.not. c_associated(this%recv_ptr))
then
202 call neko_error(
'MPI_Win_allocate failed for gs_mpi_rma data window')
205 disp_unit = int(c_sizeof(i8_dummy))
206 win_size = int(2*
pe_size, mpi_address_kind) * &
207 int(disp_unit, mpi_address_kind)
208 call mpi_win_allocate(win_size, disp_unit, info,
neko_comm, &
209 this%sig_ptr, this%win_sig, ierr)
210 if (.not. c_associated(this%sig_ptr))
then
211 call neko_error(
'MPI_Win_allocate failed for gs_mpi_rma signal window')
214 call mpi_info_free(info, ierr)
215 this%win_alloc = .true.
220 call c_f_pointer(this%sig_ptr, sig, [2*
pe_size])
225 call mpi_win_get_attr(this%win_sig, mpi_win_model, attr_val, flag, ierr)
226 this%unified = flag .and. (int(attr_val) .eq. mpi_win_unified)
228 call mpi_win_lock_all(mpi_mode_nocheck, this%win_data, ierr)
229 call mpi_win_lock_all(mpi_mode_nocheck, this%win_sig, ierr)
238 do i = 1,
size(this%recv_pe)
239 local_disp(this%recv_pe(i)) = this%recv_offset(i)
241 call mpi_alltoall(local_disp, 1, mpi_integer, &
242 remote_disp, 1, mpi_integer,
neko_comm, ierr)
243 do i = 1,
size(this%send_pe)
244 this%send_rdisp(i) = remote_disp(this%send_pe(i))
246 deallocate(local_disp, remote_disp)
249 this%vec_supported = .true.
254 this%vec_ready = .true.
267 if (this%win_alloc)
then
272 call mpi_win_unlock_all(this%win_sig, ierr)
273 call mpi_win_unlock_all(this%win_data, ierr)
274 call mpi_win_free(this%win_sig, ierr)
275 call mpi_win_free(this%win_data, ierr)
276 this%win_alloc = .false.
278 this%recv_ptr = c_null_ptr
279 this%sig_ptr = c_null_ptr
283 if (
allocated(this%send_buf))
deallocate(this%send_buf)
284 if (
allocated(this%send_ndofs))
deallocate(this%send_ndofs)
285 if (
allocated(this%send_offset))
deallocate(this%send_offset)
286 if (
allocated(this%send_rdisp))
deallocate(this%send_rdisp)
287 if (
allocated(this%recv_ndofs))
deallocate(this%recv_ndofs)
288 if (
allocated(this%recv_offset))
deallocate(this%recv_offset)
290 call this%free_order()
291 call this%free_dofs()
306 integer(kind=i8),
volatile :: s(:)
307 integer,
intent(in) :: slot
308 integer(kind=i8) :: v
322 integer,
intent(in) :: slot
323 integer(kind=i8),
intent(in) :: val
324 integer(kind=i8),
pointer :: sig(:)
325 type(mpi_status) :: status
326 integer :: spin, ierr
329 call c_f_pointer(this%sig_ptr, sig, [2*
pe_size])
336 if (.not. this%unified)
call mpi_win_sync(this%win_sig, ierr)
345 call mpi_iprobe(mpi_any_source, mpi_any_tag,
neko_comm, flag, &
357 integer,
intent(in) :: n
358 real(kind=
rp),
dimension(n),
intent(inout) :: u
359 integer,
intent(in) :: tag
360 type(c_ptr),
intent(inout) :: deps
361 type(c_ptr),
intent(inout) :: strm
362 integer(kind=MPI_ADDRESS_KIND) :: rdisp
363 integer,
pointer :: sp(:)
364 integer :: i, j, dst, base, ndst, ierr
370 this%iter = this%iter + 1
374 do i = 1,
size(this%send_pe)
375 dst = this%send_pe(i)
376 base = this%send_offset(i)
377 ndst = this%send_ndofs(i)
378 sp => this%send_dof(dst)%array()
386 this%send_buf(base + j) = u(sp(j))
396 rdisp = int(this%send_rdisp(i), mpi_address_kind)
407 rdisp = int(
pe_rank, mpi_address_kind)
408 do i = 1,
size(this%send_pe)
409 dst = this%send_pe(i)
411 call mpi_win_flush(dst, this%win_data, ierr)
413 call mpi_accumulate(this%iter, 1, mpi_integer8, dst, rdisp, 1, &
414 mpi_integer8, mpi_replace, this%win_sig, ierr)
416 call mpi_win_flush_all(this%win_sig, ierr)
425 integer,
intent(in) :: tag
433 integer,
intent(in) :: n
434 real(kind=
rp),
dimension(n),
intent(inout) :: u
435 type(c_ptr),
intent(inout) :: strm
437 integer(kind=MPI_ADDRESS_KIND) :: rdisp
438 integer,
pointer ::
sp(:)
439 real(kind=
rp),
pointer :: recv_data(:)
440 integer :: i, j, src, base, nsrc, ierr
442 call c_f_pointer(this%recv_ptr, recv_data, [
max(this%recv_total, 1)])
447 do i = 1,
size(this%recv_pe)
448 src = this%recv_pe(i)
449 base = this%recv_offset(i)
450 nsrc = this%recv_ndofs(i)
457 sp => this%recv_dof(src)%array()
467 u(
sp(j)) = u(
sp(j)) + recv_data(base + j)
478 u(
sp(j)) = u(
sp(j)) * recv_data(base + j)
489 u(
sp(j)) = min(u(
sp(j)), recv_data(base + j))
500 u(
sp(j)) =
max(u(
sp(j)), recv_data(base + j))
504 call neko_error(
"Unknown operation in gs_mpi_rma_nbwait")
511 call mpi_accumulate(this%iter, 1, mpi_integer8, src, rdisp, 1, &
512 mpi_integer8, mpi_replace, this%win_sig, ierr)
519 call mpi_win_flush_all(this%win_sig, ierr)
531 integer,
intent(in) :: n, nc
532 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
533 integer,
intent(in) :: tag
534 type(c_ptr),
intent(inout) :: deps
535 type(c_ptr),
intent(inout) :: strm
536 integer(kind=MPI_ADDRESS_KIND) :: rdisp
537 integer,
pointer :: sp(:)
538 integer :: i, j, c, dst, base, ndst, ierr
541 this%iter = this%iter + 1
545 do i = 1,
size(this%send_pe)
546 dst = this%send_pe(i)
547 base = this%send_offset(i)
548 ndst = this%send_ndofs(i)
549 sp => this%send_dof(dst)%array()
553 this%send_buf(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
561 rdisp = int(nc*this%send_rdisp(i), mpi_address_kind)
562 call mpi_put(this%send_buf(nc*base + 1), nc*ndst, &
570 rdisp = int(
pe_rank, mpi_address_kind)
571 do i = 1,
size(this%send_pe)
572 dst = this%send_pe(i)
574 call mpi_win_flush(dst, this%win_data, ierr)
576 call mpi_accumulate(this%iter, 1, mpi_integer8, dst, rdisp, 1, &
577 mpi_integer8, mpi_replace, this%win_sig, ierr)
579 call mpi_win_flush_all(this%win_sig, ierr)
588 integer,
intent(in) :: tag, nc
596 integer,
intent(in) :: n, nc
597 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
598 type(c_ptr),
intent(inout) :: strm
600 integer(kind=MPI_ADDRESS_KIND) :: rdisp
601 integer,
pointer ::
sp(:)
602 real(kind=
rp),
pointer :: recv_data(:)
603 integer :: i, j, c, src, base, nsrc, ierr
605 call c_f_pointer(this%recv_ptr, recv_data, [
max(nc*this%recv_total, 1)])
607 do i = 1,
size(this%recv_pe)
608 src = this%recv_pe(i)
609 base = this%recv_offset(i)
610 nsrc = this%recv_ndofs(i)
617 sp => this%recv_dof(src)%array()
623 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
624 recv_data(nc*base + (c-1)*nsrc + j)
632 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
633 recv_data(nc*base + (c-1)*nsrc + j)
641 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
642 recv_data(nc*base + (c-1)*nsrc + j))
650 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
651 recv_data(nc*base + (c-1)*nsrc + j))
656 call neko_error(
"Unknown operation in gs_mpi_rma_nbwait_vec")
661 call mpi_accumulate(this%iter, 1, mpi_integer8, src, rdisp, 1, &
662 mpi_integer8, mpi_replace, this%win_sig, ierr)
667 call mpi_win_flush_all(this%win_sig, ierr)
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
integer, public pe_size
MPI size of communicator.
integer, public pe_rank
MPI rank.
type(mpi_comm), public neko_comm
MPI communicator.
Defines a gather-scatter communication method.
integer, parameter, public gs_vec_nc
Maximum number of components handled by the fused vector (multi-component) halo exchange used by gs_o...
Defines MPI one-sided (RMA) gather-scatter communication.
logical, parameter, public gs_mpi_rma_avail
MPI RMA needs nothing beyond MPI-3, so the backend is always built. Kept as a parameter for symmetry ...
subroutine gs_mpi_rma_nbsend_vec(this, u, n, nc, tag, deps, strm)
Fused nc-component send: pack nc contiguous component blocks per peer slab and put nc*ndofs reals....
subroutine gs_mpi_rma_nbrecv_vec(this, tag, nc)
No-op: receives are completed by the remote put and its signal.
integer, parameter gs_mpi_rma_poke
Number of spin iterations between the progress pokes in gs_mpi_rma_wait_ge.
subroutine gs_mpi_rma_nbwait_vec(this, u, n, nc, op, strm)
Fused nc-component wait/reduce: per peer, wait on the data signal and reduce nc component blocks into...
subroutine gs_mpi_rma_free(this)
Deallocate MPI RMA based communication method.
integer(kind=i8) function gs_mpi_rma_load(s, slot)
Reload a signal counter through a VOLATILE dummy, so the spin in gs_mpi_rma_wait_ge reads memory on e...
subroutine gs_mpi_rma_nbwait(this, u, n, op, strm)
Wait per neighbour for the signal that its data has landed, reduce the slab into u,...
logical, save gs_mpi_rma_flush_bound
Whether the flush strategy has been read from the environment. It is a program-wide binding,...
subroutine gs_mpi_rma_nbsend(this, u, n, tag, deps, strm)
Pack the gathered shared dofs and put them into each neighbour's receive window, then announce the pu...
subroutine gs_mpi_rma_wait_ge(this, slot, val)
Spin until the local signal counter in slot slot has reached val. Called by the master thread only.
subroutine gs_mpi_rma_init(this, send_pe, recv_pe)
Initialise MPI RMA based communication method.
logical, save gs_mpi_rma_flush_all
Whether to complete the payload puts with a single MPI_Win_flush_all rather than one MPI_Win_flush pe...
subroutine gs_mpi_rma_nbrecv(this, tag)
No-op: receives are completed by the remote put and its signal.
Defines Gather-scatter operations.
integer, parameter, public gs_op_add
integer, parameter, public gs_op_max
integer, parameter, public gs_op_min
integer, parameter, public gs_op_mul
integer, parameter, public i8
integer, parameter, public sp
integer, parameter, public rp
Global precision used in computations.
Implements a dynamic stack ADT.
Gather-scatter communication method.
Gather-scatter communication using MPI one-sided puts into a passive target window,...