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.
447 allocate(dest_xchg(0:
pe_size - 1)[*])
449 dest_xchg(me - 1)[this%recv_img(i)] = this%recv_offset(i)
453 this%dest_offset(i) = dest_xchg(this%send_pe(i))
455 deallocate(dest_xchg)
461 allocate(in_neigh(0:
pe_size - 1))
464 in_neigh(this%send_pe(i)) = .true.
467 in_neigh(this%recv_pe(i)) = .true.
469 n_neigh = count(in_neigh)
470 allocate(this%peer(n_neigh))
473 if (in_neigh(i))
then
474 n_neigh = n_neigh + 1
475 this%peer(n_neigh) = i
483 if (.not.
allocated(gs_caf_peer_parity))
then
484 allocate(gs_caf_peer_parity(0:
pe_size - 1))
485 gs_caf_peer_parity = 0
489 allocate(this%sync_img(
size(this%peer)))
490 this%sync_img = this%peer + 1
491#ifdef HAVE_COARRAY_EVENTS
495 call gs_caf_event_drain()
498 gs_caf_event_in_use = .false.
506 call neko_error(
"Coarray Fortran support not built; reconfigure with " // &
507 "a coarray-capable Fortran compiler")
515 class(
gs_caf_t),
intent(inout) :: this
517 if (
allocated(this%send_buf))
deallocate(this%send_buf)
518 if (
allocated(this%send_len))
deallocate(this%send_len)
519 if (
allocated(this%recv_len))
deallocate(this%recv_len)
520 if (
allocated(this%send_offset))
deallocate(this%send_offset)
521 if (
allocated(this%recv_offset))
deallocate(this%recv_offset)
522 if (
allocated(this%dest_offset))
deallocate(this%dest_offset)
523 if (
allocated(this%send_img))
deallocate(this%send_img)
524 if (
allocated(this%recv_img))
deallocate(this%recv_img)
525 if (
allocated(this%peer))
deallocate(this%peer)
526 if (
allocated(this%sync_img))
deallocate(this%sync_img)
528 call this%free_order()
529 call this%free_dofs()
535#ifdef HAVE_COARRAY_EVENTS
556 subroutine gs_caf_event_drain()
559 call event_query(gs_caf_buf_ready_ev, pending)
560 if (pending .gt. 0)
then
561 event wait(gs_caf_buf_ready_ev, until_count=pending)
564 call event_query(gs_caf_data_ready_ev, pending)
565 if (pending .gt. 0)
then
566 event wait(gs_caf_data_ready_ev, until_count=pending)
569 end subroutine gs_caf_event_drain
580 class(
gs_caf_t),
intent(inout) :: this
581 integer,
intent(in) :: n
582 real(kind=
rp),
dimension(n),
intent(inout) :: u
583 integer,
intent(in) :: tag
584 type(c_ptr),
intent(inout) :: deps
585 type(c_ptr),
intent(inout) :: strm
587 integer :: i, j, dst, off, dimg, ndst, doff, half_off
588 integer,
pointer :: sp(:)
589 integer(kind=atomic_int_kind) :: flag
590 integer :: me_rank, thrdid
609 do i = 1,
size(this%send_pe)
610 dst = this%send_pe(i)
611 off = this%send_offset(i)
612 ndst = this%send_len(i)
613 dimg = this%send_img(i)
614 doff = this%dest_offset(i)
615 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
616 sp => this%send_dof(dst)%array()
624 this%send_buf(off + j) = u(sp(j))
627 if (thrdid .eq. 0)
then
628 gs_caf_recv_buf(half_off + doff + 1 : half_off + doff + ndst)[dimg] &
629 = this%send_buf(off + 1 : off + ndst)
633#ifdef HAVE_COARRAY_EVENTS
637 if (thrdid .eq. 0)
then
641 if (gs_caf_event_in_use)
then
642 call neko_error(
"Event-mode coarray gather-scatter does not " // &
643 "support overlapping gs ops on different instances")
645 gs_caf_event_in_use = .true.
649 if (this%send_started)
then
650 if (
size(this%send_pe) .gt. 0)
then
651 event wait(gs_caf_buf_ready_ev, until_count=
size(this%send_pe))
654 this%send_started = .true.
661 do i = 1,
size(this%send_pe)
662 dst = this%send_pe(i)
663 off = this%send_offset(i)
664 ndst = this%send_len(i)
665 dimg = this%send_img(i)
666 doff = this%dest_offset(i)
667 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
668 sp => this%send_dof(dst)%array()
676 this%send_buf(off + j) = u(sp(j))
679 if (thrdid .eq. 0)
then
680 gs_caf_recv_buf(half_off + doff + 1 : half_off + doff + ndst)[dimg] &
681 = this%send_buf(off + 1 : off + ndst)
689 event post(gs_caf_data_ready_ev[dimg])
698 do i = 1,
size(this%send_pe)
699 dst = this%send_pe(i)
700 off = this%send_offset(i)
701 ndst = this%send_len(i)
702 sp => this%send_dof(dst)%array()
710 this%send_buf(off + j) = u(sp(j))
719 if (thrdid .eq. 0)
then
720 me_rank = this_image() - 1
721 do i = 1,
size(this%send_pe)
722 dst = this%send_pe(i)
723 off = this%send_offset(i)
724 ndst = this%send_len(i)
725 dimg = this%send_img(i)
726 doff = this%dest_offset(i)
727 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
730 call atomic_ref(flag, gs_caf_buf_ready(this%send_pe(i)))
731 if (int(flag) .ge. gs_caf_send_count(this%send_pe(i)) - 1)
exit
734 gs_caf_recv_buf(half_off + doff + 1 : half_off + doff + ndst)[dimg] &
735 = this%send_buf(off + 1 : off + ndst)
737 gs_caf_send_count(this%send_pe(i)) = &
738 gs_caf_send_count(this%send_pe(i)) + 1
739 call atomic_define(gs_caf_data_ready(me_rank)[dimg], &
740 int(gs_caf_send_count(this%send_pe(i)), atomic_int_kind))
746 call neko_error(
"Coarray Fortran support not built")
753 class(
gs_caf_t),
intent(inout) :: this
754 integer,
intent(in) :: tag
762 class(
gs_caf_t),
intent(inout) :: this
763 integer,
intent(in) :: n
764 real(kind=
rp),
dimension(n),
intent(inout) :: u
765 type(c_ptr),
intent(inout) :: strm
768 integer :: i, j, src, off, nsrc, half_off
769 integer,
pointer ::
sp(:)
770 integer(kind=atomic_int_kind) :: flag
771 integer :: me_rank, thrdid
779 if (thrdid .eq. 0)
then
781 if (
allocated(this%sync_img))
then
782 if (
size(this%sync_img) .gt. 0)
then
783 sync images(this%sync_img)
786#ifdef HAVE_COARRAY_EVENTS
788 if (
size(this%recv_pe) .gt. 0)
then
789 event wait(gs_caf_data_ready_ev, until_count=
size(this%recv_pe))
795 do i = 1,
size(this%recv_pe)
796 gs_caf_recv_count(this%recv_pe(i)) = &
797 gs_caf_recv_count(this%recv_pe(i)) + 1
799 call atomic_ref(flag, gs_caf_data_ready(this%recv_pe(i)))
800 if (int(flag) .ge. gs_caf_recv_count(this%recv_pe(i)))
exit
811 do i = 1,
size(this%recv_pe)
812 src = this%recv_pe(i)
813 off = this%recv_offset(i)
814 nsrc = this%recv_len(i)
815 half_off = gs_caf_peer_parity(src) * gs_caf_buf_size
816 sp => this%recv_dof(src)%array()
826 u(
sp(j)) = u(
sp(j)) + gs_caf_recv_buf(half_off + off + j)
837 u(
sp(j)) = u(
sp(j)) * gs_caf_recv_buf(half_off + off + j)
848 u(
sp(j)) = min(u(
sp(j)), gs_caf_recv_buf(half_off + off + j))
859 u(
sp(j)) =
max(u(
sp(j)), gs_caf_recv_buf(half_off + off + j))
863 call neko_error(
"Unknown operation in gs_nbwait_caf")
870 if (thrdid .eq. 0)
then
874 me_rank = this_image() - 1
875 do i = 1,
size(this%recv_pe)
876 call atomic_define(gs_caf_buf_ready(me_rank)[this%recv_img(i)], &
877 int(gs_caf_recv_count(this%recv_pe(i)), atomic_int_kind))
879#ifdef HAVE_COARRAY_EVENTS
881 do i = 1,
size(this%recv_pe)
882 event post(gs_caf_buf_ready_ev[this%recv_img(i)])
884 gs_caf_event_in_use = .false.
890 do i = 1,
size(this%peer)
891 gs_caf_peer_parity(this%peer(i)) = &
892 1 - gs_caf_peer_parity(this%peer(i))
897 call neko_error(
"Coarray Fortran support not built")
906 class(
gs_caf_t),
intent(inout) :: this
907 integer,
intent(in) :: n, nc
908 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
909 integer,
intent(in) :: tag
910 type(c_ptr),
intent(inout) :: deps
911 type(c_ptr),
intent(inout) :: strm
913 integer :: i, j, c, dst, off, dimg, ndst, doff, half_off
914 integer,
pointer :: sp(:)
915 integer(kind=atomic_int_kind) :: flag
916 integer :: me_rank, thrdid
926 do i = 1,
size(this%send_pe)
927 dst = this%send_pe(i)
928 off = this%send_offset(i)
929 ndst = this%send_len(i)
930 dimg = this%send_img(i)
931 doff = this%dest_offset(i)
932 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
933 sp => this%send_dof(dst)%array()
937 this%send_buf(nc*off + (c-1)*ndst + j) = u((c-1)*n + sp(j))
941 if (thrdid .eq. 0)
then
942 gs_caf_recv_buf(half_off + nc*doff + 1 : half_off + nc*doff + nc*ndst) &
943 [dimg] = this%send_buf(nc*off + 1 : nc*off + nc*ndst)
947#ifdef HAVE_COARRAY_EVENTS
949 if (thrdid .eq. 0)
then
950 if (gs_caf_event_in_use)
then
951 call neko_error(
"Event-mode coarray gather-scatter does not " // &
952 "support overlapping gs ops on different instances")
954 gs_caf_event_in_use = .true.
956 if (this%send_started)
then
957 if (
size(this%send_pe) .gt. 0)
then
958 event wait(gs_caf_buf_ready_ev, until_count=
size(this%send_pe))
961 this%send_started = .true.
966 do i = 1,
size(this%send_pe)
967 dst = this%send_pe(i)
968 off = this%send_offset(i)
969 ndst = this%send_len(i)
970 dimg = this%send_img(i)
971 doff = this%dest_offset(i)
972 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
973 sp => this%send_dof(dst)%array()
977 this%send_buf(nc*off + (c-1)*ndst + j) = u((c-1)*n + sp(j))
981 if (thrdid .eq. 0)
then
982 gs_caf_recv_buf(half_off + nc*doff + 1 : half_off + nc*doff + nc*ndst) &
983 [dimg] = this%send_buf(nc*off + 1 : nc*off + nc*ndst)
991 event post(gs_caf_data_ready_ev[dimg])
997 do i = 1,
size(this%send_pe)
998 dst = this%send_pe(i)
999 off = this%send_offset(i)
1000 ndst = this%send_len(i)
1001 sp => this%send_dof(dst)%array()
1005 this%send_buf(nc*off + (c-1)*ndst + j) = u((c-1)*n + sp(j))
1011 if (thrdid .eq. 0)
then
1012 me_rank = this_image() - 1
1013 do i = 1,
size(this%send_pe)
1014 dst = this%send_pe(i)
1015 off = this%send_offset(i)
1016 ndst = this%send_len(i)
1017 dimg = this%send_img(i)
1018 doff = this%dest_offset(i)
1019 half_off = gs_caf_peer_parity(dst) * gs_caf_buf_size
1022 call atomic_ref(flag, gs_caf_buf_ready(this%send_pe(i)))
1023 if (int(flag) .ge. gs_caf_send_count(this%send_pe(i)) - 1)
exit
1026 gs_caf_recv_buf(half_off + nc*doff + 1 : half_off + nc*doff + nc*ndst) &
1027 [dimg] = this%send_buf(nc*off + 1 : nc*off + nc*ndst)
1029 gs_caf_send_count(this%send_pe(i)) = &
1030 gs_caf_send_count(this%send_pe(i)) + 1
1031 call atomic_define(gs_caf_data_ready(me_rank)[dimg], &
1032 int(gs_caf_send_count(this%send_pe(i)), atomic_int_kind))
1038 call neko_error(
"Coarray Fortran support not built")
1044 class(
gs_caf_t),
intent(inout) :: this
1045 integer,
intent(in) :: tag, nc
1050 class(
gs_caf_t),
intent(inout) :: this
1051 integer,
intent(in) :: n, nc
1052 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
1053 type(c_ptr),
intent(inout) :: strm
1056 integer :: i, j, c, src, off, nsrc, half_off
1057 integer,
pointer ::
sp(:)
1058 integer(kind=atomic_int_kind) :: flag
1059 integer :: me_rank, thrdid
1063 if (thrdid .eq. 0)
then
1065 if (
allocated(this%sync_img))
then
1066 if (
size(this%sync_img) .gt. 0)
then
1067 sync images(this%sync_img)
1070#ifdef HAVE_COARRAY_EVENTS
1072 if (
size(this%recv_pe) .gt. 0)
then
1073 event wait(gs_caf_data_ready_ev, until_count=
size(this%recv_pe))
1077 do i = 1,
size(this%recv_pe)
1078 gs_caf_recv_count(this%recv_pe(i)) = &
1079 gs_caf_recv_count(this%recv_pe(i)) + 1
1081 call atomic_ref(flag, gs_caf_data_ready(this%recv_pe(i)))
1082 if (int(flag) .ge. gs_caf_recv_count(this%recv_pe(i)))
exit
1091 do i = 1,
size(this%recv_pe)
1092 src = this%recv_pe(i)
1093 off = this%recv_offset(i)
1094 nsrc = this%recv_len(i)
1095 half_off = gs_caf_peer_parity(src) * gs_caf_buf_size
1096 sp => this%recv_dof(src)%array()
1102 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) + &
1103 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j)
1111 u((c-1)*n +
sp(j)) = u((c-1)*n +
sp(j)) * &
1112 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j)
1120 u((c-1)*n +
sp(j)) = min(u((c-1)*n +
sp(j)), &
1121 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j))
1129 u((c-1)*n +
sp(j)) =
max(u((c-1)*n +
sp(j)), &
1130 gs_caf_recv_buf(half_off + nc*off + (c-1)*nsrc + j))
1135 call neko_error(
"Unknown operation in gs_nbwait_vec_caf")
1139 if (thrdid .eq. 0)
then
1141 me_rank = this_image() - 1
1142 do i = 1,
size(this%recv_pe)
1143 call atomic_define(gs_caf_buf_ready(me_rank)[this%recv_img(i)], &
1144 int(gs_caf_recv_count(this%recv_pe(i)), atomic_int_kind))
1146#ifdef HAVE_COARRAY_EVENTS
1148 do i = 1,
size(this%recv_pe)
1149 event post(gs_caf_buf_ready_ev[this%recv_img(i)])
1151 gs_caf_event_in_use = .false.
1155 do i = 1,
size(this%peer)
1156 gs_caf_peer_parity(this%peer(i)) = 1 - gs_caf_peer_parity(this%peer(i))
1161 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.