40 use,
intrinsic :: iso_c_binding
41#ifdef HAVE_COARRAY_EVENTS
42 use,
intrinsic :: iso_fortran_env, only : atomic_int_kind, event_type
44 use,
intrinsic :: iso_fortran_env, only : atomic_int_kind
55 logical,
parameter,
public :: GS_CAF_AVAIL = .true.
57 logical,
parameter,
public :: gs_caf_avail = .false.
88 real(kind=
rp),
allocatable :: gs_caf_recv_buf(:)[:]
89 integer :: gs_caf_buf_size = 0
117 integer,
allocatable :: gs_caf_peer_parity(:)
122 integer :: gs_caf_mode = 0
129 integer(kind=atomic_int_kind),
allocatable :: gs_caf_data_ready(:)[:]
130 integer(kind=atomic_int_kind),
allocatable :: gs_caf_buf_ready(:)[:]
139 integer,
allocatable :: gs_caf_send_count(:)
140 integer,
allocatable :: gs_caf_recv_count(:)
142#ifdef HAVE_COARRAY_EVENTS
154 type(event_type),
allocatable :: gs_caf_data_ready_ev[:]
155 type(event_type),
allocatable :: gs_caf_buf_ready_ev[:]
156 logical :: gs_caf_event_in_use = .false.
173 real(kind=
rp),
allocatable :: send_buf(:)
175 integer,
allocatable :: send_len(:), recv_len(:)
177 integer,
allocatable :: send_offset(:), recv_offset(:)
179 integer,
allocatable :: dest_offset(:)
181 integer,
allocatable :: send_img(:), recv_img(:)
185 integer,
allocatable :: peer(:)
189 integer,
allocatable :: sync_img(:)
192 logical :: send_started = .false.
222 usable = (num_images() .eq.
pe_size)
236 character(len=64) :: env_val
239 call get_environment_variable(
"NEKO_GS_CAF_SIGNALING", env_val, env_len)
240 auto = (env_len .gt. 0)
241 if (auto) auto = (env_val(1:env_len) .eq.
"auto")
250 integer,
allocatable :: mode(:)
256#ifdef HAVE_COARRAY_EVENTS
283 integer,
intent(in) :: mode
284 character(len=12) :: name
295 call neko_error(
'Unknown coarray gather-scatter signaling mode')
309 integer,
intent(in) :: mode
317 if (.not.
allocated(gs_caf_data_ready))
then
318 allocate(gs_caf_data_ready(0:
pe_size - 1)[*])
319 allocate(gs_caf_buf_ready(0:
pe_size - 1)[*])
320 allocate(gs_caf_send_count(0:
pe_size - 1))
321 allocate(gs_caf_recv_count(0:
pe_size - 1))
322 gs_caf_send_count = 0
323 gs_caf_recv_count = 0
328 call atomic_define(gs_caf_data_ready(i), 0_atomic_int_kind)
329 call atomic_define(gs_caf_buf_ready(i), 0_atomic_int_kind)
333#ifdef HAVE_COARRAY_EVENTS
336 if (.not.
allocated(gs_caf_data_ready_ev))
then
337 allocate(gs_caf_data_ready_ev[*])
338 allocate(gs_caf_buf_ready_ev[*])
341 call neko_error(
"NEKO_GS_CAF_SIGNALING=event requires a Fortran " // &
342 "compiler with coarray events support")
345 call neko_error(
'Unknown coarray gather-scatter signaling mode')
350 call neko_error(
"Coarray Fortran support not built; reconfigure with " // &
351 "a coarray-capable Fortran compiler")
357 class(
gs_caf_t),
intent(inout) :: this
361 integer,
allocatable :: dest_xchg(:)[:]
362 logical,
allocatable :: in_neigh(:)
363 integer :: i, nsend, nrecv, send_total, recv_total, max_total, n_neigh
364 integer :: me, env_len
365 character(len=64) :: env_val
371 call neko_error(
"Coarray gather-scatter needs one image per rank; " // &
372 "this build or run has num_images() /= pe_size")
380 if (gs_caf_mode .eq. 0)
then
381 call get_environment_variable(
"NEKO_GS_CAF_SIGNALING", env_val, env_len)
382 if (env_len .gt. 0 .and. env_val(1:env_len) .eq.
"atomic")
then
384 else if (env_len .gt. 0 .and. env_val(1:env_len) .eq.
"event")
then
391 call this%init_order(send_pe, recv_pe)
393 nsend =
size(this%send_pe)
394 nrecv =
size(this%recv_pe)
396 allocate(this%send_len(nsend), this%send_offset(nsend), &
397 this%send_img(nsend), this%dest_offset(nsend))
398 allocate(this%recv_len(nrecv), this%recv_offset(nrecv), &
399 this%recv_img(nrecv))
404 this%recv_len(i) = this%recv_dof(this%recv_pe(i))%size()
405 this%recv_offset(i) = recv_total
406 recv_total = recv_total + this%recv_len(i)
407 this%recv_img(i) = this%recv_pe(i) + 1
413 this%send_len(i) = this%send_dof(this%send_pe(i))%size()
414 this%send_offset(i) = send_total
415 send_total = send_total + this%send_len(i)
416 this%send_img(i) = this%send_pe(i) + 1
427 max_total = recv_total
428 call co_max(max_total)
429 max_total =
max(1, max_total)
434 if (
gs_vec_nc * max_total .gt. gs_caf_buf_size)
then
435 if (
allocated(gs_caf_recv_buf))
deallocate(gs_caf_recv_buf)
436 allocate(gs_caf_recv_buf(2 *
gs_vec_nc * max_total)[*])
439 this%vec_supported = .true.
444 this%vec_ready = .true.
452 allocate(dest_xchg(0:
pe_size - 1)[*])
454 dest_xchg(me - 1)[this%recv_img(i)] = this%recv_offset(i)
458 this%dest_offset(i) = dest_xchg(this%send_pe(i))
460 deallocate(dest_xchg)
466 allocate(in_neigh(0:
pe_size - 1))
469 in_neigh(this%send_pe(i)) = .true.
472 in_neigh(this%recv_pe(i)) = .true.
474 n_neigh = count(in_neigh)
475 allocate(this%peer(n_neigh))
478 if (in_neigh(i))
then
479 n_neigh = n_neigh + 1
480 this%peer(n_neigh) = i
488 if (.not.
allocated(gs_caf_peer_parity))
then
489 allocate(gs_caf_peer_parity(0:
pe_size - 1))
490 gs_caf_peer_parity = 0
494 allocate(this%sync_img(
size(this%peer)))
495 this%sync_img = this%peer + 1
496#ifdef HAVE_COARRAY_EVENTS
500 call gs_caf_event_drain()
503 gs_caf_event_in_use = .false.
511 call neko_error(
"Coarray Fortran support not built; reconfigure with " // &
512 "a coarray-capable Fortran compiler")
520 class(
gs_caf_t),
intent(inout) :: this
522 if (
allocated(this%send_buf))
deallocate(this%send_buf)
523 if (
allocated(this%send_len))
deallocate(this%send_len)
524 if (
allocated(this%recv_len))
deallocate(this%recv_len)
525 if (
allocated(this%send_offset))
deallocate(this%send_offset)
526 if (
allocated(this%recv_offset))
deallocate(this%recv_offset)
527 if (
allocated(this%dest_offset))
deallocate(this%dest_offset)
528 if (
allocated(this%send_img))
deallocate(this%send_img)
529 if (
allocated(this%recv_img))
deallocate(this%recv_img)
530 if (
allocated(this%peer))
deallocate(this%peer)
531 if (
allocated(this%sync_img))
deallocate(this%sync_img)
533 call this%free_order()
534 call this%free_dofs()
540#ifdef HAVE_COARRAY_EVENTS
561 subroutine gs_caf_event_drain()
564 call event_query(gs_caf_buf_ready_ev, pending)
565 if (pending .gt. 0)
then
566 event wait(gs_caf_buf_ready_ev, until_count=pending)
569 call event_query(gs_caf_data_ready_ev, pending)
570 if (pending .gt. 0)
then
571 event wait(gs_caf_data_ready_ev, until_count=pending)
574 end subroutine gs_caf_event_drain
585 class(
gs_caf_t),
intent(inout) :: this
586 integer,
intent(in) :: n
587 real(kind=
rp),
dimension(n),
intent(inout) :: u
588 integer,
intent(in) :: tag
589 type(c_ptr),
intent(inout) :: deps
590 type(c_ptr),
intent(inout) :: strm
592 integer :: i, j, dst, off, dimg, ndst, doff, half_off
593 integer,
pointer :: sp(:)
594 integer(kind=atomic_int_kind) :: flag
595 integer :: me_rank, thrdid
614 do i = 1,
size(this%send_pe)
615 dst = this%send_pe(i)
616 off = this%send_offset(i)
617 ndst = this%send_len(i)
618 dimg = this%send_img(i)
619 doff = this%dest_offset(i)
620 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
621 sp => this%send_dof(dst)%array()
629 this%send_buf(off + j) = u(sp(j))
632 if (thrdid .eq. 0)
then
633 gs_caf_recv_buf(half_off + doff + 1 : half_off + doff + ndst)[dimg] &
634 = this%send_buf(off + 1 : off + ndst)
638#ifdef HAVE_COARRAY_EVENTS
642 if (thrdid .eq. 0)
then
646 if (gs_caf_event_in_use)
then
647 call neko_error(
"Event-mode coarray gather-scatter does not " // &
648 "support overlapping gs ops on different instances")
650 gs_caf_event_in_use = .true.
654 if (this%send_started)
then
655 if (
size(this%send_pe) .gt. 0)
then
656 event wait(gs_caf_buf_ready_ev, until_count=
size(this%send_pe))
659 this%send_started = .true.
666 do i = 1,
size(this%send_pe)
667 dst = this%send_pe(i)
668 off = this%send_offset(i)
669 ndst = this%send_len(i)
670 dimg = this%send_img(i)
671 doff = this%dest_offset(i)
672 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
673 sp => this%send_dof(dst)%array()
681 this%send_buf(off + j) = u(sp(j))
684 if (thrdid .eq. 0)
then
685 gs_caf_recv_buf(half_off + doff + 1 : half_off + doff + ndst)[dimg] &
686 = this%send_buf(off + 1 : off + ndst)
694 event post(gs_caf_data_ready_ev[dimg])
703 do i = 1,
size(this%send_pe)
704 dst = this%send_pe(i)
705 off = this%send_offset(i)
706 ndst = this%send_len(i)
707 sp => this%send_dof(dst)%array()
715 this%send_buf(off + j) = u(sp(j))
724 if (thrdid .eq. 0)
then
725 me_rank = this_image() - 1
726 do i = 1,
size(this%send_pe)
727 dst = this%send_pe(i)
728 off = this%send_offset(i)
729 ndst = this%send_len(i)
730 dimg = this%send_img(i)
731 doff = this%dest_offset(i)
732 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
735 call atomic_ref(flag, gs_caf_buf_ready(this%send_pe(i)))
736 if (int(flag) .ge. gs_caf_send_count(this%send_pe(i)) - 1)
exit
739 gs_caf_recv_buf(half_off + doff + 1 : half_off + doff + ndst)[dimg] &
740 = this%send_buf(off + 1 : off + ndst)
742 gs_caf_send_count(this%send_pe(i)) = &
743 gs_caf_send_count(this%send_pe(i)) + 1
744 call atomic_define(gs_caf_data_ready(me_rank)[dimg], &
745 int(gs_caf_send_count(this%send_pe(i)), atomic_int_kind))
751 call neko_error(
"Coarray Fortran support not built")
758 class(
gs_caf_t),
intent(inout) :: this
759 integer,
intent(in) :: tag
767 class(
gs_caf_t),
intent(inout) :: this
768 integer,
intent(in) :: n
769 real(kind=
rp),
dimension(n),
intent(inout) :: u
770 type(c_ptr),
intent(inout) :: strm
773 integer :: i, j, src, off, nsrc, half_off
774 integer,
pointer ::
sp(:)
775 integer(kind=atomic_int_kind) :: flag
776 integer :: me_rank, thrdid
784 if (thrdid .eq. 0)
then
786 if (
allocated(this%sync_img))
then
787 if (
size(this%sync_img) .gt. 0)
then
788 sync images(this%sync_img)
791#ifdef HAVE_COARRAY_EVENTS
793 if (
size(this%recv_pe) .gt. 0)
then
794 event wait(gs_caf_data_ready_ev, until_count=
size(this%recv_pe))
800 do i = 1,
size(this%recv_pe)
801 gs_caf_recv_count(this%recv_pe(i)) = &
802 gs_caf_recv_count(this%recv_pe(i)) + 1
804 call atomic_ref(flag, gs_caf_data_ready(this%recv_pe(i)))
805 if (int(flag) .ge. gs_caf_recv_count(this%recv_pe(i)))
exit
816 do i = 1,
size(this%recv_pe)
817 src = this%recv_pe(i)
818 off = this%recv_offset(i)
819 nsrc = this%recv_len(i)
820 half_off = gs_caf_peer_parity(src) * gs_caf_buf_size
821 sp => this%recv_dof(src)%array()
831 u(
sp(j)) = u(
sp(j)) + gs_caf_recv_buf(half_off + off + j)
842 u(
sp(j)) = u(
sp(j)) * gs_caf_recv_buf(half_off + off + j)
853 u(
sp(j)) = min(u(
sp(j)), gs_caf_recv_buf(half_off + off + j))
864 u(
sp(j)) =
max(u(
sp(j)), gs_caf_recv_buf(half_off + off + j))
868 call neko_error(
"Unknown operation in gs_nbwait_caf")
875 if (thrdid .eq. 0)
then
879 me_rank = this_image() - 1
880 do i = 1,
size(this%recv_pe)
881 call atomic_define(gs_caf_buf_ready(me_rank)[this%recv_img(i)], &
882 int(gs_caf_recv_count(this%recv_pe(i)), atomic_int_kind))
884#ifdef HAVE_COARRAY_EVENTS
886 do i = 1,
size(this%recv_pe)
887 event post(gs_caf_buf_ready_ev[this%recv_img(i)])
889 gs_caf_event_in_use = .false.
895 do i = 1,
size(this%peer)
896 gs_caf_peer_parity(this%peer(i)) = &
897 1 - gs_caf_peer_parity(this%peer(i))
902 call neko_error(
"Coarray Fortran support not built")
911 class(
gs_caf_t),
intent(inout) :: this
912 integer,
intent(in) :: n, nc
913 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
914 integer,
intent(in) :: tag
915 type(c_ptr),
intent(inout) :: deps
916 type(c_ptr),
intent(inout) :: strm
918 integer :: i, j, c, dst, off, dimg, ndst, doff, half_off
919 integer,
pointer :: sp(:)
920 integer(kind=atomic_int_kind) :: flag
921 integer :: me_rank, thrdid
931 do i = 1,
size(this%send_pe)
932 dst = this%send_pe(i)
933 off = this%send_offset(i)
934 ndst = this%send_len(i)
935 dimg = this%send_img(i)
936 doff = this%dest_offset(i)
937 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
938 sp => this%send_dof(dst)%array()
942 this%send_buf(nc*off + (c-1)*ndst + j) = u((c-1)*n + sp(j))
946 if (thrdid .eq. 0)
then
947 gs_caf_recv_buf(half_off + nc*doff + 1 : half_off + nc*doff + nc*ndst) &
948 [dimg] = this%send_buf(nc*off + 1 : nc*off + nc*ndst)
952#ifdef HAVE_COARRAY_EVENTS
954 if (thrdid .eq. 0)
then
955 if (gs_caf_event_in_use)
then
956 call neko_error(
"Event-mode coarray gather-scatter does not " // &
957 "support overlapping gs ops on different instances")
959 gs_caf_event_in_use = .true.
961 if (this%send_started)
then
962 if (
size(this%send_pe) .gt. 0)
then
963 event wait(gs_caf_buf_ready_ev, until_count=
size(this%send_pe))
966 this%send_started = .true.
971 do i = 1,
size(this%send_pe)
972 dst = this%send_pe(i)
973 off = this%send_offset(i)
974 ndst = this%send_len(i)
975 dimg = this%send_img(i)
976 doff = this%dest_offset(i)
977 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
978 sp => this%send_dof(dst)%array()
982 this%send_buf(nc*off + (c-1)*ndst + j) = u((c-1)*n + sp(j))
986 if (thrdid .eq. 0)
then
987 gs_caf_recv_buf(half_off + nc*doff + 1 : half_off + nc*doff + nc*ndst) &
988 [dimg] = this%send_buf(nc*off + 1 : nc*off + nc*ndst)
996 event post(gs_caf_data_ready_ev[dimg])
1002 do i = 1,
size(this%send_pe)
1003 dst = this%send_pe(i)
1004 off = this%send_offset(i)
1005 ndst = this%send_len(i)
1006 sp => this%send_dof(dst)%array()
1010 this%send_buf(nc*off + (c-1)*ndst + j) = u((c-1)*n + sp(j))
1016 if (thrdid .eq. 0)
then
1017 me_rank = this_image() - 1
1018 do i = 1,
size(this%send_pe)
1019 dst = this%send_pe(i)
1020 off = this%send_offset(i)
1021 ndst = this%send_len(i)
1022 dimg = this%send_img(i)
1023 doff = this%dest_offset(i)
1024 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
1027 call atomic_ref(flag, gs_caf_buf_ready(this%send_pe(i)))
1028 if (int(flag) .ge. gs_caf_send_count(this%send_pe(i)) - 1)
exit
1031 gs_caf_recv_buf(half_off + nc*doff + 1 : half_off + nc*doff + nc*ndst) &
1032 [dimg] = this%send_buf(nc*off + 1 : nc*off + nc*ndst)
1034 gs_caf_send_count(this%send_pe(i)) = &
1035 gs_caf_send_count(this%send_pe(i)) + 1
1036 call atomic_define(gs_caf_data_ready(me_rank)[dimg], &
1037 int(gs_caf_send_count(this%send_pe(i)), atomic_int_kind))
1043 call neko_error(
"Coarray Fortran support not built")
1049 class(
gs_caf_t),
intent(inout) :: this
1050 integer,
intent(in) :: tag, nc
1055 class(
gs_caf_t),
intent(inout) :: this
1056 integer,
intent(in) :: n, nc
1057 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
1058 type(c_ptr),
intent(inout) :: strm
1061 integer :: i, j, c, src, off, nsrc, half_off
1062 integer,
pointer ::
sp(:)
1063 integer(kind=atomic_int_kind) :: flag
1064 integer :: me_rank, thrdid
1068 if (thrdid .eq. 0)
then
1070 if (
allocated(this%sync_img))
then
1071 if (
size(this%sync_img) .gt. 0)
then
1072 sync images(this%sync_img)
1075#ifdef HAVE_COARRAY_EVENTS
1077 if (
size(this%recv_pe) .gt. 0)
then
1078 event wait(gs_caf_data_ready_ev, until_count=
size(this%recv_pe))
1082 do i = 1,
size(this%recv_pe)
1083 gs_caf_recv_count(this%recv_pe(i)) = &
1084 gs_caf_recv_count(this%recv_pe(i)) + 1
1086 call atomic_ref(flag, gs_caf_data_ready(this%recv_pe(i)))
1087 if (int(flag) .ge. gs_caf_recv_count(this%recv_pe(i)))
exit
1096 do i = 1,
size(this%recv_pe)
1097 src = this%recv_pe(i)
1098 off = this%recv_offset(i)
1099 nsrc = this%recv_len(i)
1100 half_off = gs_caf_peer_parity(src) * gs_caf_buf_size
1101 sp => this%recv_dof(src)%array()
1107 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
1108 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j)
1116 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
1117 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j)
1125 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
1126 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j))
1134 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
1135 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j))
1140 call neko_error(
"Unknown operation in gs_nbwait_vec_caf")
1144 if (thrdid .eq. 0)
then
1146 me_rank = this_image() - 1
1147 do i = 1,
size(this%recv_pe)
1148 call atomic_define(gs_caf_buf_ready(me_rank)[this%recv_img(i)], &
1149 int(gs_caf_recv_count(this%recv_pe(i)), atomic_int_kind))
1151#ifdef HAVE_COARRAY_EVENTS
1153 do i = 1,
size(this%recv_pe)
1154 event post(gs_caf_buf_ready_ev[this%recv_img(i)])
1156 gs_caf_event_in_use = .false.
1160 do i = 1,
size(this%peer)
1161 gs_caf_peer_parity(this%peer(i)) = 1 - gs_caf_peer_parity(this%peer(i))
1166 call neko_error(
"Coarray Fortran support not built")
integer, public pe_size
MPI size of communicator.
Defines Coarray Fortran gather-scatter communication.
subroutine gs_nbrecv_caf(this, tag)
No-op for coarrays: senders push into the receiver's buffer, so the receive side does not need to pos...
subroutine gs_nbrecv_vec_caf(this, tag, nc)
No-op: senders push into the receiver's buffer.
subroutine gs_nbsend_caf(this, u, n, tag, deps, strm)
Pack u into per-peer slabs and put each slab into the remote image's recv_buf. Double buffering means...
subroutine gs_caf_init(this, send_pe, recv_pe)
Initialise Coarray Fortran based communication method.
subroutine gs_nbwait_caf(this, u, n, op, strm)
Wait for all incoming puts and reduce them into u. In sync mode a sync_images bracket pairs with the ...
integer function, public gs_caf_mode_get()
The signaling mode currently in force, or 0 if none has been bound yet (no gs_caf_t has been initiali...
integer, parameter, public gs_caf_signal_event
integer function, dimension(:), allocatable, public gs_caf_signal_modes()
The signaling modes this build can run, in the order they should be benchmarked. Events are only avai...
logical function, public gs_caf_usable()
Whether the coarray backend can actually run in this job. GS_CAF_AVAIL only says that the compiler ac...
subroutine, public gs_caf_set_mode(mode)
Bind the signaling mode shared by every gs_caf_t instance, allocating whatever module-level state the...
character(len=12) function, public gs_caf_mode_name(mode)
Name of the signaling mode mode, right-adjusted for the log.
subroutine gs_nbsend_vec_caf(this, u, n, nc, tag, deps, strm)
Fused nc-component put. Each peer slab is nc consecutive component blocks; the remote placement offse...
integer, parameter, public gs_caf_signal_atomic
subroutine gs_caf_free(this)
Deallocate Coarray Fortran based communication method. The shared module-level recv coarray is intent...
integer, parameter, public gs_caf_signal_sync
subroutine gs_nbwait_vec_caf(this, u, n, nc, op, strm)
Fused nc-component wait/reduce for the coarray backend.
logical function, public gs_caf_signal_auto()
Whether the signaling mode should be selected by benchmarking, i.e. NEKO_GS_CAF_SIGNALING=auto....
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
integer, parameter, public sp
integer, parameter, public rp
Global precision used in computations.
Implements a dynamic stack ADT.
Gather-scatter communication using Coarray Fortran (F2008). Each image puts directly into the (module...
Gather-scatter communication method.