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.
294 if (c_associated(this%data_signals_ptr))
then
297 if (c_associated(this%ack_signals_ptr))
then
300 this%data_signals_ptr = c_null_ptr
301 this%ack_signals_ptr = c_null_ptr
305 call this%send_buf%free()
306 call this%recv_buf%free()
308 call this%free_order()
309 call this%free_dofs()
320 integer,
intent(in) :: n
321 real(kind=
rp),
dimension(n),
intent(inout) :: u
322 integer,
intent(in) :: tag
323 type(c_ptr),
intent(inout) :: deps
324 type(c_ptr),
intent(inout) :: strm
325 integer :: i, j, dst, base, ndst
326 integer(c_size_t) :: nbytes
327 integer ,
pointer :: sp(:)
328 real(kind=
rp),
pointer :: send_data(:), recv_data(:)
329 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
330 real(c_rp) :: rp_dummy
340 this%iter = this%iter + 1
343 call c_f_pointer(this%send_buf%buf_ptr, send_data, &
344 [
max(this%send_buf%max_total, 1)])
345 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
346 [
max(this%recv_buf%max_total, 1)])
347 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
348 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
357 do i = 1,
size(this%send_pe)
358 dst = this%send_pe(i)
367 sp => this%send_dof(dst)%array()
368 base = this%send_buf%offset(i)
369 ndst = this%send_buf%ndofs(i)
370 do concurrent(j = 1:ndst)
371 send_data(base + j) = u(sp(j))
374 nbytes = int(ndst, c_size_t) * c_sizeof(rp_dummy)
377 c_loc(recv_data(this%send_buf%remote_offset(i) + 1)), &
378 c_loc(send_data(base + 1)), &
380 c_loc(data_signals(
pe_rank + 1)), &
392 do i = 1,
size(this%send_pe)
393 dst = this%send_pe(i)
394 base = this%send_buf%offset(i)
395 ndst = this%send_buf%ndofs(i)
403 sp => this%send_dof(dst)%array()
411 send_data(base + j) = u(sp(j))
416 nbytes = int(ndst, c_size_t) * c_sizeof(rp_dummy)
418 c_loc(recv_data(this%send_buf%remote_offset(i) + 1)), &
419 c_loc(send_data(base + 1)), &
421 c_loc(data_signals(
pe_rank + 1)), &
433 integer,
intent(in) :: tag
442 integer,
intent(in) :: n
443 real(kind=
rp),
dimension(n),
intent(inout) :: u
444 type(c_ptr),
intent(inout) :: strm
446 integer :: i, j, src, base, nsrc
447 integer(c_int64_t) :: dummy
448 integer ,
pointer ::
sp(:)
449 real(kind=
rp),
pointer :: recv_data(:)
450 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
453 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
454 [
max(this%recv_buf%max_total, 1)])
455 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
456 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
463 do i = 1,
size(this%recv_pe)
464 src = this%recv_pe(i)
465 base = this%recv_buf%offset(i)
466 nsrc = this%recv_buf%ndofs(i)
475 sp => this%recv_dof(src)%array()
485 u(
sp(j)) = u(
sp(j)) + recv_data(base + j)
496 u(
sp(j)) = u(
sp(j)) * recv_data(base + j)
507 u(
sp(j)) = min(u(
sp(j)), recv_data(base + j))
518 u(
sp(j)) =
max(u(
sp(j)), recv_data(base + j))
522 call neko_error(
"Unknown operation in gs_nbwait_shmem")
532 c_loc(ack_signals(
pe_rank + 1)), &
545 integer,
intent(in) :: n, nc
546 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
547 integer,
intent(in) :: tag
548 type(c_ptr),
intent(inout) :: deps
549 type(c_ptr),
intent(inout) :: strm
550 integer :: i, j, c, dst, base, ndst
551 integer(c_size_t) :: nbytes
552 integer,
pointer :: sp(:)
553 real(kind=
rp),
pointer :: send_data(:), recv_data(:)
554 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
555 real(c_rp) :: rp_dummy
559 this%iter = this%iter + 1
562 call c_f_pointer(this%send_buf%buf_ptr, send_data, &
563 [
max(nc*this%send_buf%max_total, 1)])
564 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
565 [
max(nc*this%recv_buf%max_total, 1)])
566 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
567 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
574 do i = 1,
size(this%send_pe)
575 dst = this%send_pe(i)
580 sp => this%send_dof(dst)%array()
581 base = this%send_buf%offset(i)
582 ndst = this%send_buf%ndofs(i)
584 do concurrent(j = 1:ndst)
585 send_data(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
589 nbytes = int(nc*ndst, c_size_t) * c_sizeof(rp_dummy)
591 c_loc(recv_data(nc*this%send_buf%remote_offset(i) + 1)), &
592 c_loc(send_data(nc*base + 1)), &
594 c_loc(data_signals(
pe_rank + 1)), &
599 do i = 1,
size(this%send_pe)
600 dst = this%send_pe(i)
601 base = this%send_buf%offset(i)
602 ndst = this%send_buf%ndofs(i)
610 sp => this%send_dof(dst)%array()
614 send_data(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
620 nbytes = int(nc*ndst, c_size_t) * c_sizeof(rp_dummy)
622 c_loc(recv_data(nc*this%send_buf%remote_offset(i) + 1)), &
623 c_loc(send_data(nc*base + 1)), &
625 c_loc(data_signals(
pe_rank + 1)), &
637 integer,
intent(in) :: tag, nc
644 integer,
intent(in) :: n, nc
645 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
646 type(c_ptr),
intent(inout) :: strm
648 integer :: i, j, c, src, base, nsrc
649 integer(c_int64_t) :: dummy
650 integer,
pointer ::
sp(:)
651 real(kind=
rp),
pointer :: recv_data(:)
652 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
655 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
656 [
max(nc*this%recv_buf%max_total, 1)])
657 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
658 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
662 do i = 1,
size(this%recv_pe)
663 src = this%recv_pe(i)
664 base = this%recv_buf%offset(i)
665 nsrc = this%recv_buf%ndofs(i)
673 sp => this%recv_dof(src)%array()
679 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
680 recv_data(nc*base + (c-1)*nsrc + j)
688 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
689 recv_data(nc*base + (c-1)*nsrc + j)
697 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
698 recv_data(nc*base + (c-1)*nsrc + j))
706 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
707 recv_data(nc*base + (c-1)*nsrc + j))
712 call neko_error(
"Unknown operation in gs_shmem_nbwait_vec")
717 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...