40 use mpi_f08,
only : mpi_allreduce, mpi_alltoall, mpi_integer, mpi_max
49 use,
intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr, c_loc, &
50 c_f_pointer, c_associated, c_sizeof, c_size_t, c_int64_t, c_int
74 integer,
allocatable :: ndofs(:)
76 integer,
allocatable :: offset(:)
79 integer,
allocatable :: remote_offset(:)
83 integer :: max_total = 0
85 type(c_ptr) :: buf_ptr = c_null_ptr
122 type(c_ptr) :: data_signals_ptr = c_null_ptr
126 type(c_ptr) :: ack_signals_ptr = c_null_ptr
131 integer(kind=i8) :: iter = 0
151 integer,
intent(in) :: pe_order(:)
152 type(
stack_i4_t),
intent(inout) :: dof_stack(0:)
153 integer :: i, ierr, n
154 integer(c_size_t) :: sz
155 real(c_rp) :: rp_dummy
156#ifndef HAVE_OPENSHMEM
157 call neko_error(
'Neko was not built with OpenSHMEM support')
162 allocate(this%ndofs(n))
163 allocate(this%offset(n))
164 allocate(this%remote_offset(n))
167 this%remote_offset(i) = -1
172 this%ndofs(i) = dof_stack(pe_order(i))%size()
173 this%offset(i) = this%total
174 this%total = this%total + this%ndofs(i)
179 call mpi_allreduce(this%total, this%max_total, 1, mpi_integer, mpi_max, &
185 sz = c_sizeof(rp_dummy) * int(
max(
gs_vec_nc*this%max_total, 1), c_size_t)
187 if (.not. c_associated(this%buf_ptr))
then
188 call neko_error(
'shmem_malloc failed for gs_shmem buffer')
197 if (
allocated(this%ndofs))
deallocate(this%ndofs)
198 if (
allocated(this%offset))
deallocate(this%offset)
199 if (
allocated(this%remote_offset))
deallocate(this%remote_offset)
202 if (c_associated(this%buf_ptr))
then
208 this%buf_ptr = c_null_ptr
220 integer(c_size_t) :: i64_size
221 integer(c_int64_t) :: i64_dummy
222 integer,
allocatable :: local_offsets(:), remote_offsets(:)
224 integer(c_int) :: thread_level
226#ifndef HAVE_OPENSHMEM
227 call neko_error(
'Neko was not built with OpenSHMEM support')
234 call this%init_order(send_pe, recv_pe)
241 call this%send_buf%init(this%send_pe, this%send_dof)
242 call this%recv_buf%init(this%recv_pe, this%recv_dof)
247 i64_size = c_sizeof(i64_dummy)
249 if (.not. c_associated(this%data_signals_ptr))
then
250 call neko_error(
'shmem_calloc failed for gs_shmem data signals')
253 if (.not. c_associated(this%ack_signals_ptr))
then
254 call neko_error(
'shmem_calloc failed for gs_shmem ack signals')
262 allocate(local_offsets(0:
pe_size - 1))
263 allocate(remote_offsets(0:
pe_size - 1))
265 do i = 1,
size(this%recv_pe)
266 local_offsets(this%recv_pe(i)) = this%recv_buf%offset(i)
268 call mpi_alltoall(local_offsets, 1, mpi_integer, &
269 remote_offsets, 1, mpi_integer,
neko_comm, ierr)
270 do i = 1,
size(this%send_pe)
271 this%send_buf%remote_offset(i) = remote_offsets(this%send_pe(i))
273 deallocate(local_offsets)
274 deallocate(remote_offsets)
277 this%vec_supported = .true.
282 this%vec_ready = .true.
299 if (c_associated(this%data_signals_ptr))
then
302 if (c_associated(this%ack_signals_ptr))
then
305 this%data_signals_ptr = c_null_ptr
306 this%ack_signals_ptr = c_null_ptr
310 call this%send_buf%free()
311 call this%recv_buf%free()
313 call this%free_order()
314 call this%free_dofs()
325 integer,
intent(in) :: n
326 real(kind=
rp),
dimension(n),
intent(inout) :: u
327 integer,
intent(in) :: tag
328 type(c_ptr),
intent(inout) :: deps
329 type(c_ptr),
intent(inout) :: strm
330 integer :: i, j, dst, base, ndst
331 integer(c_size_t) :: nbytes
332 integer ,
pointer :: sp(:)
333 real(kind=
rp),
pointer :: send_data(:), recv_data(:)
334 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
335 real(c_rp) :: rp_dummy
345 this%iter = this%iter + 1
348 call c_f_pointer(this%send_buf%buf_ptr, send_data, &
349 [
max(this%send_buf%max_total, 1)])
350 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
351 [
max(this%recv_buf%max_total, 1)])
352 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
353 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
362 do i = 1,
size(this%send_pe)
363 dst = this%send_pe(i)
372 sp => this%send_dof(dst)%array()
373 base = this%send_buf%offset(i)
374 ndst = this%send_buf%ndofs(i)
375 do concurrent(j = 1:ndst)
376 send_data(base + j) = u(sp(j))
379 nbytes = int(ndst, c_size_t) * c_sizeof(rp_dummy)
382 c_loc(recv_data(this%send_buf%remote_offset(i) + 1)), &
383 c_loc(send_data(base + 1)), &
385 c_loc(data_signals(
pe_rank + 1)), &
397 do i = 1,
size(this%send_pe)
398 dst = this%send_pe(i)
399 base = this%send_buf%offset(i)
400 ndst = this%send_buf%ndofs(i)
408 sp => this%send_dof(dst)%array()
416 send_data(base + j) = u(sp(j))
421 nbytes = int(ndst, c_size_t) * c_sizeof(rp_dummy)
423 c_loc(recv_data(this%send_buf%remote_offset(i) + 1)), &
424 c_loc(send_data(base + 1)), &
426 c_loc(data_signals(
pe_rank + 1)), &
438 integer,
intent(in) :: tag
447 integer,
intent(in) :: n
448 real(kind=
rp),
dimension(n),
intent(inout) :: u
449 type(c_ptr),
intent(inout) :: strm
451 integer :: i, j, src, base, nsrc
452 integer(c_int64_t) :: dummy
453 integer ,
pointer ::
sp(:)
454 real(kind=
rp),
pointer :: recv_data(:)
455 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
458 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
459 [
max(this%recv_buf%max_total, 1)])
460 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
461 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
468 do i = 1,
size(this%recv_pe)
469 src = this%recv_pe(i)
470 base = this%recv_buf%offset(i)
471 nsrc = this%recv_buf%ndofs(i)
480 sp => this%recv_dof(src)%array()
490 u(
sp(j)) = u(
sp(j)) + recv_data(base + j)
501 u(
sp(j)) = u(
sp(j)) * recv_data(base + j)
512 u(
sp(j)) = min(u(
sp(j)), recv_data(base + j))
523 u(
sp(j)) =
max(u(
sp(j)), recv_data(base + j))
527 call neko_error(
"Unknown operation in gs_nbwait_shmem")
537 c_loc(ack_signals(
pe_rank + 1)), &
550 integer,
intent(in) :: n, nc
551 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
552 integer,
intent(in) :: tag
553 type(c_ptr),
intent(inout) :: deps
554 type(c_ptr),
intent(inout) :: strm
555 integer :: i, j, c, dst, base, ndst
556 integer(c_size_t) :: nbytes
557 integer,
pointer :: sp(:)
558 real(kind=
rp),
pointer :: send_data(:), recv_data(:)
559 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
560 real(c_rp) :: rp_dummy
564 this%iter = this%iter + 1
567 call c_f_pointer(this%send_buf%buf_ptr, send_data, &
568 [
max(nc*this%send_buf%max_total, 1)])
569 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
570 [
max(nc*this%recv_buf%max_total, 1)])
571 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
572 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
579 do i = 1,
size(this%send_pe)
580 dst = this%send_pe(i)
585 sp => this%send_dof(dst)%array()
586 base = this%send_buf%offset(i)
587 ndst = this%send_buf%ndofs(i)
589 do concurrent(j = 1:ndst)
590 send_data(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
594 nbytes = int(nc*ndst, c_size_t) * c_sizeof(rp_dummy)
596 c_loc(recv_data(nc*this%send_buf%remote_offset(i) + 1)), &
597 c_loc(send_data(nc*base + 1)), &
599 c_loc(data_signals(
pe_rank + 1)), &
604 do i = 1,
size(this%send_pe)
605 dst = this%send_pe(i)
606 base = this%send_buf%offset(i)
607 ndst = this%send_buf%ndofs(i)
615 sp => this%send_dof(dst)%array()
619 send_data(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
625 nbytes = int(nc*ndst, c_size_t) * c_sizeof(rp_dummy)
627 c_loc(recv_data(nc*this%send_buf%remote_offset(i) + 1)), &
628 c_loc(send_data(nc*base + 1)), &
630 c_loc(data_signals(
pe_rank + 1)), &
642 integer,
intent(in) :: tag, nc
649 integer,
intent(in) :: n, nc
650 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
651 type(c_ptr),
intent(inout) :: strm
653 integer :: i, j, c, src, base, nsrc
654 integer(c_int64_t) :: dummy
655 integer,
pointer ::
sp(:)
656 real(kind=
rp),
pointer :: recv_data(:)
657 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
660 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
661 [
max(nc*this%recv_buf%max_total, 1)])
662 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
663 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
667 do i = 1,
size(this%recv_pe)
668 src = this%recv_pe(i)
669 base = this%recv_buf%offset(i)
670 nsrc = this%recv_buf%ndofs(i)
678 sp => this%recv_dof(src)%array()
684 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
685 recv_data(nc*base + (c-1)*nsrc + j)
693 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
694 recv_data(nc*base + (c-1)*nsrc + j)
702 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
703 recv_data(nc*base + (c-1)*nsrc + j))
711 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
712 recv_data(nc*base + (c-1)*nsrc + j))
717 call neko_error(
"Unknown operation in gs_shmem_nbwait_vec")
722 c_loc(ack_signals(
pe_rank + 1)), &
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 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
Defines OpenSHMEM gather-scatter communication.
subroutine gs_shmem_buf_init(this, pe_order, dof_stack)
Allocate symmetric memory and per-neighbor bookkeeping for one direction of communication.
subroutine gs_shmem_nbrecv_vec(this, tag, nc)
No-op: receives are completed via remote put-with-signal.
logical, parameter, public gs_shmem_avail
Whether a native OpenSHMEM library was built into this Neko (–with-openshmem). Lets callers (e....
subroutine gs_shmem_init(this, send_pe, recv_pe)
Initialise OpenSHMEM based communication method.
subroutine gs_shmem_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_shmem_nbsend(this, u, n, tag, deps, strm)
Pack the gathered shared dofs into the symmetric send buffer and issue non-blocking puts with signali...
subroutine gs_shmem_buf_free(this)
Release symmetric memory and bookkeeping.
subroutine gs_shmem_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 wit...
subroutine gs_shmem_free(this)
Deallocate OpenSHMEM based communication method.
subroutine gs_shmem_nbrecv(this, tag)
No-op: receives are completed via remote put-with-signal.
logical gs_shmem_thread_multiple
True when the OpenSHMEM library provides SHMEM_THREAD_MULTIPLE. The send path then lets each OpenMP t...
subroutine gs_shmem_nbwait(this, u, n, op, strm)
Wait per-neighbor for the signal indicating that data has landed, apply the gather-scatter operation ...
integer, parameter, public i8
integer, parameter, public sp
integer, parameter, public c_rp
integer, parameter, public rp
Global precision used in computations.
Fortran bindings to SHMEM's C API.
Implements a dynamic stack ADT.
Gather-scatter communication method.
Symmetric buffer for one direction of OpenSHMEM communication.
Gather-scatter communication using OpenSHMEM one-sided puts with per-rank signaling for completion (O...