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.
262 if (this%win_alloc)
then
267 call mpi_win_unlock_all(this%win_sig, ierr)
268 call mpi_win_unlock_all(this%win_data, ierr)
269 call mpi_win_free(this%win_sig, ierr)
270 call mpi_win_free(this%win_data, ierr)
271 this%win_alloc = .false.
273 this%recv_ptr = c_null_ptr
274 this%sig_ptr = c_null_ptr
278 if (
allocated(this%send_buf))
deallocate(this%send_buf)
279 if (
allocated(this%send_ndofs))
deallocate(this%send_ndofs)
280 if (
allocated(this%send_offset))
deallocate(this%send_offset)
281 if (
allocated(this%send_rdisp))
deallocate(this%send_rdisp)
282 if (
allocated(this%recv_ndofs))
deallocate(this%recv_ndofs)
283 if (
allocated(this%recv_offset))
deallocate(this%recv_offset)
285 call this%free_order()
286 call this%free_dofs()
301 integer(kind=i8),
volatile :: s(:)
302 integer,
intent(in) :: slot
303 integer(kind=i8) :: v
317 integer,
intent(in) :: slot
318 integer(kind=i8),
intent(in) :: val
319 integer(kind=i8),
pointer :: sig(:)
320 type(mpi_status) :: status
321 integer :: spin, ierr
324 call c_f_pointer(this%sig_ptr, sig, [2*
pe_size])
331 if (.not. this%unified)
call mpi_win_sync(this%win_sig, ierr)
340 call mpi_iprobe(mpi_any_source, mpi_any_tag,
neko_comm, flag, &
352 integer,
intent(in) :: n
353 real(kind=
rp),
dimension(n),
intent(inout) :: u
354 integer,
intent(in) :: tag
355 type(c_ptr),
intent(inout) :: deps
356 type(c_ptr),
intent(inout) :: strm
357 integer(kind=MPI_ADDRESS_KIND) :: rdisp
358 integer,
pointer :: sp(:)
359 integer :: i, j, dst, base, ndst, ierr
365 this%iter = this%iter + 1
369 do i = 1,
size(this%send_pe)
370 dst = this%send_pe(i)
371 base = this%send_offset(i)
372 ndst = this%send_ndofs(i)
373 sp => this%send_dof(dst)%array()
381 this%send_buf(base + j) = u(sp(j))
391 rdisp = int(this%send_rdisp(i), mpi_address_kind)
402 rdisp = int(
pe_rank, mpi_address_kind)
403 do i = 1,
size(this%send_pe)
404 dst = this%send_pe(i)
406 call mpi_win_flush(dst, this%win_data, ierr)
408 call mpi_accumulate(this%iter, 1, mpi_integer8, dst, rdisp, 1, &
409 mpi_integer8, mpi_replace, this%win_sig, ierr)
411 call mpi_win_flush_all(this%win_sig, ierr)
420 integer,
intent(in) :: tag
428 integer,
intent(in) :: n
429 real(kind=
rp),
dimension(n),
intent(inout) :: u
430 type(c_ptr),
intent(inout) :: strm
432 integer(kind=MPI_ADDRESS_KIND) :: rdisp
433 integer,
pointer ::
sp(:)
434 real(kind=
rp),
pointer :: recv_data(:)
435 integer :: i, j, src, base, nsrc, ierr
437 call c_f_pointer(this%recv_ptr, recv_data, [
max(this%recv_total, 1)])
442 do i = 1,
size(this%recv_pe)
443 src = this%recv_pe(i)
444 base = this%recv_offset(i)
445 nsrc = this%recv_ndofs(i)
452 sp => this%recv_dof(src)%array()
462 u(
sp(j)) = u(
sp(j)) + recv_data(base + j)
473 u(
sp(j)) = u(
sp(j)) * recv_data(base + j)
484 u(
sp(j)) = min(u(
sp(j)), recv_data(base + j))
495 u(
sp(j)) =
max(u(
sp(j)), recv_data(base + j))
499 call neko_error(
"Unknown operation in gs_mpi_rma_nbwait")
506 call mpi_accumulate(this%iter, 1, mpi_integer8, src, rdisp, 1, &
507 mpi_integer8, mpi_replace, this%win_sig, ierr)
514 call mpi_win_flush_all(this%win_sig, ierr)
526 integer,
intent(in) :: n, nc
527 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
528 integer,
intent(in) :: tag
529 type(c_ptr),
intent(inout) :: deps
530 type(c_ptr),
intent(inout) :: strm
531 integer(kind=MPI_ADDRESS_KIND) :: rdisp
532 integer,
pointer :: sp(:)
533 integer :: i, j, c, dst, base, ndst, ierr
536 this%iter = this%iter + 1
540 do i = 1,
size(this%send_pe)
541 dst = this%send_pe(i)
542 base = this%send_offset(i)
543 ndst = this%send_ndofs(i)
544 sp => this%send_dof(dst)%array()
548 this%send_buf(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
556 rdisp = int(nc*this%send_rdisp(i), mpi_address_kind)
557 call mpi_put(this%send_buf(nc*base + 1), nc*ndst, &
565 rdisp = int(
pe_rank, mpi_address_kind)
566 do i = 1,
size(this%send_pe)
567 dst = this%send_pe(i)
569 call mpi_win_flush(dst, this%win_data, ierr)
571 call mpi_accumulate(this%iter, 1, mpi_integer8, dst, rdisp, 1, &
572 mpi_integer8, mpi_replace, this%win_sig, ierr)
574 call mpi_win_flush_all(this%win_sig, ierr)
583 integer,
intent(in) :: tag, nc
591 integer,
intent(in) :: n, nc
592 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
593 type(c_ptr),
intent(inout) :: strm
595 integer(kind=MPI_ADDRESS_KIND) :: rdisp
596 integer,
pointer ::
sp(:)
597 real(kind=
rp),
pointer :: recv_data(:)
598 integer :: i, j, c, src, base, nsrc, ierr
600 call c_f_pointer(this%recv_ptr, recv_data, [
max(nc*this%recv_total, 1)])
602 do i = 1,
size(this%recv_pe)
603 src = this%recv_pe(i)
604 base = this%recv_offset(i)
605 nsrc = this%recv_ndofs(i)
612 sp => this%recv_dof(src)%array()
618 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
619 recv_data(nc*base + (c-1)*nsrc + j)
627 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
628 recv_data(nc*base + (c-1)*nsrc + j)
636 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
637 recv_data(nc*base + (c-1)*nsrc + j))
645 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
646 recv_data(nc*base + (c-1)*nsrc + j))
651 call neko_error(
"Unknown operation in gs_mpi_rma_nbwait_vec")
656 call mpi_accumulate(this%iter, 1, mpi_integer8, src, rdisp, 1, &
657 mpi_integer8, mpi_replace, this%win_sig, ierr)
662 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,...