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(:)
83 integer,
allocatable :: send_rdisp(:)
97 type(mpi_win) :: win_data
99 type(c_ptr) :: recv_ptr = c_null_ptr
101 integer,
allocatable :: recv_ndofs(:)
104 integer,
allocatable :: recv_offset(:)
106 integer :: recv_total = 0
109 type(mpi_win) :: win_sig
111 type(c_ptr) :: sig_ptr = c_null_ptr
116 integer(kind=i8) :: iter = 0
121 logical :: unified = .true.
125 logical :: win_alloc = .false.
144 type(mpi_info) :: info
145 integer(kind=MPI_ADDRESS_KIND) :: win_size, attr_val
146 integer,
allocatable :: local_disp(:), remote_disp(:)
147 integer(kind=i8),
pointer :: sig(:)
148 integer :: i, n, send_total, ierr, disp_unit, env_len
149 integer(kind=i8) :: i8_dummy
150 real(kind=
rp) :: rp_dummy
151 character(len=255) :: env_val
157 call this%init_order(send_pe, recv_pe)
162 call get_environment_variable(
"NEKO_GS_RMA_FLUSH_ALL", env_val, env_len)
163 if (env_len .gt. 0)
then
164 env_len = min(env_len, len(env_val))
171 n =
size(this%send_pe)
172 allocate(this%send_ndofs(n), this%send_offset(n), this%send_rdisp(n))
175 this%send_ndofs(i) = this%send_dof(this%send_pe(i))%size()
176 this%send_offset(i) = send_total
177 send_total = send_total + this%send_ndofs(i)
183 n =
size(this%recv_pe)
184 allocate(this%recv_ndofs(n), this%recv_offset(n))
187 this%recv_ndofs(i) = this%recv_dof(this%recv_pe(i))%size()
188 this%recv_offset(i) = this%recv_total
189 this%recv_total = this%recv_total + this%recv_ndofs(i)
204 call mpi_info_create(info, ierr)
205 call mpi_info_set(info,
'same_disp_unit',
'true', ierr)
206 call mpi_info_set(info,
'accumulate_ordering',
'none', ierr)
207 call mpi_info_set(info,
'accumulate_ops',
'same_op', ierr)
209 disp_unit = int(c_sizeof(rp_dummy))
210 win_size = int(
max(
gs_vec_nc*this%recv_total, 1), mpi_address_kind) * &
211 int(disp_unit, mpi_address_kind)
212 call mpi_win_allocate(win_size, disp_unit, info,
neko_comm, &
213 this%recv_ptr, this%win_data, ierr)
214 if (.not. c_associated(this%recv_ptr))
then
215 call neko_error(
'MPI_Win_allocate failed for gs_mpi_rma data window')
218 disp_unit = int(c_sizeof(i8_dummy))
219 win_size = int(2*
pe_size, mpi_address_kind) * &
220 int(disp_unit, mpi_address_kind)
221 call mpi_win_allocate(win_size, disp_unit, info,
neko_comm, &
222 this%sig_ptr, this%win_sig, ierr)
223 if (.not. c_associated(this%sig_ptr))
then
224 call neko_error(
'MPI_Win_allocate failed for gs_mpi_rma signal window')
227 call mpi_info_free(info, ierr)
228 this%win_alloc = .true.
233 call c_f_pointer(this%sig_ptr, sig, [2*
pe_size])
238 call mpi_win_get_attr(this%win_sig, mpi_win_model, attr_val, flag, ierr)
239 this%unified = flag .and. (int(attr_val) .eq. mpi_win_unified)
241 call mpi_win_lock_all(mpi_mode_nocheck, this%win_data, ierr)
242 call mpi_win_lock_all(mpi_mode_nocheck, this%win_sig, ierr)
251 do i = 1,
size(this%recv_pe)
252 local_disp(this%recv_pe(i)) = this%recv_offset(i)
254 call mpi_alltoall(local_disp, 1, mpi_integer, &
255 remote_disp, 1, mpi_integer,
neko_comm, ierr)
256 do i = 1,
size(this%send_pe)
257 this%send_rdisp(i) = remote_disp(this%send_pe(i))
259 deallocate(local_disp, remote_disp)
262 this%vec_supported = .true.
267 this%vec_ready = .true.
280 if (this%win_alloc)
then
285 call mpi_win_unlock_all(this%win_sig, ierr)
286 call mpi_win_unlock_all(this%win_data, ierr)
287 call mpi_win_free(this%win_sig, ierr)
288 call mpi_win_free(this%win_data, ierr)
289 this%win_alloc = .false.
291 this%recv_ptr = c_null_ptr
292 this%sig_ptr = c_null_ptr
296 if (
allocated(this%send_buf))
deallocate(this%send_buf)
297 if (
allocated(this%send_ndofs))
deallocate(this%send_ndofs)
298 if (
allocated(this%send_offset))
deallocate(this%send_offset)
299 if (
allocated(this%send_rdisp))
deallocate(this%send_rdisp)
300 if (
allocated(this%recv_ndofs))
deallocate(this%recv_ndofs)
301 if (
allocated(this%recv_offset))
deallocate(this%recv_offset)
303 call this%free_order()
304 call this%free_dofs()
319 integer(kind=i8),
volatile :: s(:)
320 integer,
intent(in) :: slot
321 integer(kind=i8) :: v
335 integer,
intent(in) :: slot
336 integer(kind=i8),
intent(in) :: val
337 integer(kind=i8),
pointer :: sig(:)
338 type(mpi_status) :: status
339 integer :: spin, ierr
342 call c_f_pointer(this%sig_ptr, sig, [2*
pe_size])
349 if (.not. this%unified)
call mpi_win_sync(this%win_sig, ierr)
358 call mpi_iprobe(mpi_any_source, mpi_any_tag,
neko_comm, flag, &
370 integer,
intent(in) :: n
371 real(kind=
rp),
dimension(n),
intent(inout) :: u
372 integer,
intent(in) :: tag
373 type(c_ptr),
intent(inout) :: deps
374 type(c_ptr),
intent(inout) :: strm
375 integer(kind=MPI_ADDRESS_KIND) :: rdisp
376 integer,
pointer :: sp(:)
377 integer :: i, j, dst, base, ndst, ierr
383 this%iter = this%iter + 1
387 do i = 1,
size(this%send_pe)
388 dst = this%send_pe(i)
389 base = this%send_offset(i)
390 ndst = this%send_ndofs(i)
391 sp => this%send_dof(dst)%array()
399 this%send_buf(base + j) = u(sp(j))
409 rdisp = int(
gs_vec_nc*this%send_rdisp(i), mpi_address_kind)
420 rdisp = int(
pe_rank, mpi_address_kind)
421 do i = 1,
size(this%send_pe)
422 dst = this%send_pe(i)
424 call mpi_win_flush(dst, this%win_data, ierr)
426 call mpi_accumulate(this%iter, 1, mpi_integer8, dst, rdisp, 1, &
427 mpi_integer8, mpi_replace, this%win_sig, ierr)
429 call mpi_win_flush_all(this%win_sig, ierr)
438 integer,
intent(in) :: tag
446 integer,
intent(in) :: n
447 real(kind=
rp),
dimension(n),
intent(inout) :: u
448 type(c_ptr),
intent(inout) :: strm
450 integer(kind=MPI_ADDRESS_KIND) :: rdisp
451 integer,
pointer ::
sp(:)
452 real(kind=
rp),
pointer :: recv_data(:)
453 integer :: i, j, src, base, nsrc, ierr
455 call c_f_pointer(this%recv_ptr, recv_data, &
461 do i = 1,
size(this%recv_pe)
462 src = this%recv_pe(i)
464 nsrc = this%recv_ndofs(i)
471 sp => this%recv_dof(src)%array()
481 u(
sp(j)) = u(
sp(j)) + recv_data(base + j)
492 u(
sp(j)) = u(
sp(j)) * recv_data(base + j)
503 u(
sp(j)) = min(u(
sp(j)), recv_data(base + j))
514 u(
sp(j)) =
max(u(
sp(j)), recv_data(base + j))
518 call neko_error(
"Unknown operation in gs_mpi_rma_nbwait")
525 call mpi_accumulate(this%iter, 1, mpi_integer8, src, rdisp, 1, &
526 mpi_integer8, mpi_replace, this%win_sig, ierr)
533 call mpi_win_flush_all(this%win_sig, ierr)
546 integer,
intent(in) :: n, nc
547 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
548 integer,
intent(in) :: tag
549 type(c_ptr),
intent(inout) :: deps
550 type(c_ptr),
intent(inout) :: strm
551 integer(kind=MPI_ADDRESS_KIND) :: rdisp
552 integer,
pointer :: sp(:)
553 integer :: i, j, c, dst, base, ndst, ierr
556 this%iter = this%iter + 1
560 do i = 1,
size(this%send_pe)
561 dst = this%send_pe(i)
562 base = this%send_offset(i)
563 ndst = this%send_ndofs(i)
564 sp => this%send_dof(dst)%array()
568 this%send_buf(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
576 rdisp = int(
gs_vec_nc*this%send_rdisp(i), mpi_address_kind)
577 call mpi_put(this%send_buf(nc*base + 1), nc*ndst, &
585 rdisp = int(
pe_rank, mpi_address_kind)
586 do i = 1,
size(this%send_pe)
587 dst = this%send_pe(i)
589 call mpi_win_flush(dst, this%win_data, ierr)
591 call mpi_accumulate(this%iter, 1, mpi_integer8, dst, rdisp, 1, &
592 mpi_integer8, mpi_replace, this%win_sig, ierr)
594 call mpi_win_flush_all(this%win_sig, ierr)
603 integer,
intent(in) :: tag, nc
611 integer,
intent(in) :: n, nc
612 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
613 type(c_ptr),
intent(inout) :: strm
615 integer(kind=MPI_ADDRESS_KIND) :: rdisp
616 integer,
pointer ::
sp(:)
617 real(kind=
rp),
pointer :: recv_data(:)
618 integer :: i, j, c, src, base, nsrc, ierr
620 call c_f_pointer(this%recv_ptr, recv_data, &
623 do i = 1,
size(this%recv_pe)
624 src = this%recv_pe(i)
627 nsrc = this%recv_ndofs(i)
634 sp => this%recv_dof(src)%array()
640 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
641 recv_data(base + (c-1)*nsrc + j)
649 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
650 recv_data(base + (c-1)*nsrc + j)
658 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
659 recv_data(base + (c-1)*nsrc + j))
667 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
668 recv_data(base + (c-1)*nsrc + j))
673 call neko_error(
"Unknown operation in gs_mpi_rma_nbwait_vec")
678 call mpi_accumulate(this%iter, 1, mpi_integer8, src, rdisp, 1, &
679 mpi_integer8, mpi_replace, this%win_sig, ierr)
684 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 int...
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,...