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, &
194 sz = c_sizeof(rp_dummy) * int(
max(
gs_vec_nc*this%max_total, 1), c_size_t)
196 if (.not. c_associated(this%buf_ptr))
then
197 call neko_error(
'shmem_malloc failed for gs_shmem buffer')
206 if (
allocated(this%ndofs))
deallocate(this%ndofs)
207 if (
allocated(this%offset))
deallocate(this%offset)
208 if (
allocated(this%remote_offset))
deallocate(this%remote_offset)
211 if (c_associated(this%buf_ptr))
then
217 this%buf_ptr = c_null_ptr
229 integer(c_size_t) :: i64_size
230 integer(c_int64_t) :: i64_dummy
231 integer,
allocatable :: local_offsets(:), remote_offsets(:)
233 integer(c_int) :: thread_level
235#ifndef HAVE_OPENSHMEM
236 call neko_error(
'Neko was not built with OpenSHMEM support')
243 call this%init_order(send_pe, recv_pe)
250 call this%send_buf%init(this%send_pe, this%send_dof)
251 call this%recv_buf%init(this%recv_pe, this%recv_dof)
256 i64_size = c_sizeof(i64_dummy)
258 if (.not. c_associated(this%data_signals_ptr))
then
259 call neko_error(
'shmem_calloc failed for gs_shmem data signals')
262 if (.not. c_associated(this%ack_signals_ptr))
then
263 call neko_error(
'shmem_calloc failed for gs_shmem ack signals')
271 allocate(local_offsets(0:
pe_size - 1))
272 allocate(remote_offsets(0:
pe_size - 1))
274 do i = 1,
size(this%recv_pe)
275 local_offsets(this%recv_pe(i)) = this%recv_buf%offset(i)
277 call mpi_alltoall(local_offsets, 1, mpi_integer, &
278 remote_offsets, 1, mpi_integer,
neko_comm, ierr)
279 do i = 1,
size(this%send_pe)
280 this%send_buf%remote_offset(i) = remote_offsets(this%send_pe(i))
282 deallocate(local_offsets)
283 deallocate(remote_offsets)
286 this%vec_supported = .true.
291 this%vec_ready = .true.
308 if (c_associated(this%data_signals_ptr))
then
311 if (c_associated(this%ack_signals_ptr))
then
314 this%data_signals_ptr = c_null_ptr
315 this%ack_signals_ptr = c_null_ptr
319 call this%send_buf%free()
320 call this%recv_buf%free()
322 call this%free_order()
323 call this%free_dofs()
334 integer,
intent(in) :: n
335 real(kind=
rp),
dimension(n),
intent(inout) :: u
336 integer,
intent(in) :: tag
337 type(c_ptr),
intent(inout) :: deps
338 type(c_ptr),
intent(inout) :: strm
339 integer :: i, j, dst, base, ndst
340 integer(c_size_t) :: nbytes
341 integer ,
pointer :: sp(:)
342 real(kind=
rp),
pointer :: send_data(:), recv_data(:)
343 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
344 real(c_rp) :: rp_dummy
354 this%iter = this%iter + 1
357 call c_f_pointer(this%send_buf%buf_ptr, send_data, &
358 [
max(this%send_buf%max_total, 1)])
359 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
361 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
362 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
371 do i = 1,
size(this%send_pe)
372 dst = this%send_pe(i)
381 sp => this%send_dof(dst)%array()
382 base = this%send_buf%offset(i)
383 ndst = this%send_buf%ndofs(i)
384 do concurrent(j = 1:ndst)
385 send_data(base + j) = u(sp(j))
388 nbytes = int(ndst, c_size_t) * c_sizeof(rp_dummy)
391 c_loc(recv_data(
gs_vec_nc*this%send_buf%remote_offset(i) + 1)), &
392 c_loc(send_data(base + 1)), &
394 c_loc(data_signals(
pe_rank + 1)), &
406 do i = 1,
size(this%send_pe)
407 dst = this%send_pe(i)
408 base = this%send_buf%offset(i)
409 ndst = this%send_buf%ndofs(i)
417 sp => this%send_dof(dst)%array()
425 send_data(base + j) = u(sp(j))
430 nbytes = int(ndst, c_size_t) * c_sizeof(rp_dummy)
432 c_loc(recv_data(
gs_vec_nc*this%send_buf%remote_offset(i) + 1)), &
433 c_loc(send_data(base + 1)), &
435 c_loc(data_signals(
pe_rank + 1)), &
447 integer,
intent(in) :: tag
456 integer,
intent(in) :: n
457 real(kind=
rp),
dimension(n),
intent(inout) :: u
458 type(c_ptr),
intent(inout) :: strm
460 integer :: i, j, src, base, nsrc
461 integer(c_int64_t) :: dummy
462 integer ,
pointer ::
sp(:)
463 real(kind=
rp),
pointer :: recv_data(:)
464 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
467 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
469 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
470 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
477 do i = 1,
size(this%recv_pe)
478 src = this%recv_pe(i)
481 nsrc = this%recv_buf%ndofs(i)
490 sp => this%recv_dof(src)%array()
500 u(
sp(j)) = u(
sp(j)) + recv_data(base + j)
511 u(
sp(j)) = u(
sp(j)) * recv_data(base + j)
522 u(
sp(j)) = min(u(
sp(j)), recv_data(base + j))
533 u(
sp(j)) =
max(u(
sp(j)), recv_data(base + j))
537 call neko_error(
"Unknown operation in gs_nbwait_shmem")
547 c_loc(ack_signals(
pe_rank + 1)), &
560 integer,
intent(in) :: n, nc
561 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
562 integer,
intent(in) :: tag
563 type(c_ptr),
intent(inout) :: deps
564 type(c_ptr),
intent(inout) :: strm
565 integer :: i, j, c, dst, base, ndst
566 integer(c_size_t) :: nbytes
567 integer,
pointer :: sp(:)
568 real(kind=
rp),
pointer :: send_data(:), recv_data(:)
569 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
570 real(c_rp) :: rp_dummy
574 this%iter = this%iter + 1
577 call c_f_pointer(this%send_buf%buf_ptr, send_data, &
578 [
max(nc*this%send_buf%max_total, 1)])
579 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
581 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
582 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
589 do i = 1,
size(this%send_pe)
590 dst = this%send_pe(i)
595 sp => this%send_dof(dst)%array()
596 base = this%send_buf%offset(i)
597 ndst = this%send_buf%ndofs(i)
599 do concurrent(j = 1:ndst)
600 send_data(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
604 nbytes = int(nc*ndst, c_size_t) * c_sizeof(rp_dummy)
606 c_loc(recv_data(
gs_vec_nc*this%send_buf%remote_offset(i) + 1)), &
607 c_loc(send_data(nc*base + 1)), &
609 c_loc(data_signals(
pe_rank + 1)), &
614 do i = 1,
size(this%send_pe)
615 dst = this%send_pe(i)
616 base = this%send_buf%offset(i)
617 ndst = this%send_buf%ndofs(i)
625 sp => this%send_dof(dst)%array()
629 send_data(nc*base + (c-1)*ndst + j) = u((c-1)*n + sp(j))
635 nbytes = int(nc*ndst, c_size_t) * c_sizeof(rp_dummy)
637 c_loc(recv_data(
gs_vec_nc*this%send_buf%remote_offset(i) + 1)), &
638 c_loc(send_data(nc*base + 1)), &
640 c_loc(data_signals(
pe_rank + 1)), &
652 integer,
intent(in) :: tag, nc
659 integer,
intent(in) :: n, nc
660 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
661 type(c_ptr),
intent(inout) :: strm
663 integer :: i, j, c, src, base, nsrc
664 integer(c_int64_t) :: dummy
665 integer,
pointer ::
sp(:)
666 real(kind=
rp),
pointer :: recv_data(:)
667 integer(c_int64_t),
pointer :: data_signals(:), ack_signals(:)
670 call c_f_pointer(this%recv_buf%buf_ptr, recv_data, &
672 call c_f_pointer(this%data_signals_ptr, data_signals, [
pe_size])
673 call c_f_pointer(this%ack_signals_ptr, ack_signals, [
pe_size])
677 do i = 1,
size(this%recv_pe)
678 src = this%recv_pe(i)
681 nsrc = this%recv_buf%ndofs(i)
689 sp => this%recv_dof(src)%array()
695 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
696 recv_data(base + (c-1)*nsrc + j)
704 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
705 recv_data(base + (c-1)*nsrc + j)
713 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
714 recv_data(base + (c-1)*nsrc + j))
722 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
723 recv_data(base + (c-1)*nsrc + j))
728 call neko_error(
"Unknown operation in gs_shmem_nbwait_vec")
733 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...