55 use,
intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr, c_associated, &
56 c_sizeof, c_size_t, c_int32_t
65 type(c_ptr) :: buf_d(2) = c_null_ptr
67 type(c_ptr) :: sbuf_d = c_null_ptr
70 type(c_ptr) :: buf_v_d(2) = c_null_ptr
71 type(c_ptr) :: sbuf_v_d = c_null_ptr
74 type(c_ptr),
allocatable :: keep_idx_d(:), send_idx_d(:)
77 type(c_ptr),
allocatable :: keep_idx_v_d(:), send_idx_v_d(:)
79 type(c_ptr) :: pack_keep_d = c_null_ptr
80 type(c_ptr) :: pack_send_d = c_null_ptr
81 type(c_ptr) :: unpack_d = c_null_ptr
83 type(c_ptr) :: sreqs = c_null_ptr
84 type(c_ptr) :: rreqs = c_null_ptr
85 integer :: nsreq = 0, nrreq = 0
107 bind(c, name =
'hip_gs_pack')
108 use,
intrinsic :: iso_c_binding
110 integer(c_int),
value :: n, offset
111 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
117 bind(c, name =
'hip_gs_unpack')
118 use,
intrinsic :: iso_c_binding
120 integer(c_int),
value :: op, offset, n
121 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
127 bind(c, name =
'hip_gs_pack_vec')
128 use,
intrinsic :: iso_c_binding
130 integer(c_int),
value :: offset, n, nc, ns
131 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
137 stream) bind(c, name = 'hip_gs_unpack_vec')
138 use,
intrinsic :: iso_c_binding
140 integer(c_int),
value :: op, offset, n, nc, ns
141 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
146 subroutine cuda_gs_pack(u_d, buf_d, dof_d, offset, n, stream) &
147 bind(c, name =
'cuda_gs_pack')
148 use,
intrinsic :: iso_c_binding
150 integer(c_int),
value :: n, offset
151 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
156 subroutine cuda_gs_unpack(u_d, op, buf_d, dof_d, offset, n, stream) &
157 bind(c, name =
'cuda_gs_unpack')
158 use,
intrinsic :: iso_c_binding
160 integer(c_int),
value :: op, offset, n
161 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
167 bind(c, name =
'cuda_gs_pack_vec')
168 use,
intrinsic :: iso_c_binding
170 integer(c_int),
value :: offset, n, nc, ns
171 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
177 stream) bind(c, name = 'cuda_gs_unpack_vec')
178 use,
intrinsic :: iso_c_binding
180 integer(c_int),
value :: op, offset, n, nc, ns
181 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
188 bind(c, name =
'device_mpi_init_reqs')
189 use,
intrinsic :: iso_c_binding
191 integer(c_int),
value :: n
198 bind(c, name =
'device_mpi_free_reqs')
199 use,
intrinsic :: iso_c_binding
207 bind(c, name =
'device_mpi_isend')
208 use,
intrinsic :: iso_c_binding
210 integer(c_int),
value :: offset, nbytes, rank, tag, i
211 type(c_ptr),
value :: buf_d, reqs
217 bind(c, name =
'device_mpi_irecv')
218 use,
intrinsic :: iso_c_binding
220 integer(c_int),
value :: offset, nbytes, rank, tag, i
221 type(c_ptr),
value :: buf_d, reqs
227 bind(c, name =
'device_mpi_waitall')
228 use,
intrinsic :: iso_c_binding
230 integer(c_int),
value :: n
231 type(c_ptr),
value :: reqs
243 integer,
allocatable :: dofs(:)
245 integer(c_size_t) :: sz
246 real(c_rp) :: rp_dummy
248 call this%init_order(send_pe, recv_pe)
250 call this%plan%init(this%send_pe, this%recv_pe, this%send_dof, &
256 sz = c_sizeof(rp_dummy) * this%plan%nwrk
259 sz = c_sizeof(rp_dummy) * this%plan%nsmax
263 if (this%plan%nstage .gt. 0)
then
264 call cr_upload(this%pack_keep_d, this%plan%pack_keep_dof, &
265 this%plan%stage(1)%nkw)
266 call cr_upload(this%pack_send_d, this%plan%pack_send_dof, &
267 this%plan%stage(1)%nsw)
272 allocate(dofs(
max(this%plan%nfinal, 1)))
273 call cr_mark_dupes(this%plan%unpack_dof, dofs, this%plan%nfinal)
274 call cr_upload(this%unpack_d, dofs, this%plan%nfinal)
277 nst =
max(this%plan%nstage, 1)
278 allocate(this%keep_idx_d(nst), this%send_idx_d(nst))
279 allocate(this%keep_idx_v_d(nst), this%send_idx_v_d(nst))
280 this%keep_idx_d = c_null_ptr
281 this%send_idx_d = c_null_ptr
282 this%keep_idx_v_d = c_null_ptr
283 this%send_idx_v_d = c_null_ptr
286 do i = 2, this%plan%nstage
287 associate(st => this%plan%stage(i))
288 if (.not. st%inplace)
then
289 call cr_upload(this%keep_idx_d(i), st%keep_idx, st%nkw)
291 if (st%dst .ge. 0)
then
292 call cr_upload(this%send_idx_d(i), st%send_idx, st%nsw)
297 this%vec_supported = .true.
298 this%vec_ready = .false.
309 integer(c_size_t) :: sz
310 real(c_rp) :: rp_dummy
312 sz = c_sizeof(rp_dummy) *
gs_vec_nc * this%plan%nwrk
315 sz = c_sizeof(rp_dummy) *
gs_vec_nc * this%plan%nsmax
329 if (c_associated(this%buf_d(i)))
call device_free(this%buf_d(i))
330 if (c_associated(this%buf_v_d(i)))
call device_free(this%buf_v_d(i))
332 if (c_associated(this%sbuf_d))
call device_free(this%sbuf_d)
333 if (c_associated(this%sbuf_v_d))
call device_free(this%sbuf_v_d)
335 if (c_associated(this%pack_keep_d))
call device_free(this%pack_keep_d)
336 if (c_associated(this%pack_send_d))
call device_free(this%pack_send_d)
337 if (c_associated(this%unpack_d))
call device_free(this%unpack_d)
344 if (
allocated(this%keep_idx_d))
deallocate(this%keep_idx_d)
345 if (
allocated(this%send_idx_d))
deallocate(this%send_idx_d)
346 if (
allocated(this%keep_idx_v_d))
deallocate(this%keep_idx_v_d)
347 if (
allocated(this%send_idx_v_d))
deallocate(this%send_idx_v_d)
350 this%vec_ready = .false.
352 call this%plan%free()
354 call this%free_order()
355 call this%free_dofs()
362 integer,
intent(in) :: tag
367 if (this%plan%nstage .eq. 0)
return
369 associate(st => this%plan%stage(1))
370 if (st%src .ge. 0)
then
371 this%nrreq = this%nrreq + 1
373 rp*st%nrw, st%src, tag, this%rreqs, this%nrreq)
375 if (st%src2 .ge. 0)
then
376 this%nrreq = this%nrreq + 1
378 rp*(st%nkw + st%nrw),
rp*st%nr2w, st%src2, tag, &
379 this%rreqs, this%nrreq)
388 integer,
intent(in) :: n
389 real(kind=
rp),
dimension(n),
intent(inout) :: u
390 integer,
intent(in) :: tag
391 type(c_ptr),
intent(inout) :: deps
392 type(c_ptr),
intent(inout) :: strm
395 if (this%plan%nstage .eq. 0)
return
399 associate(st => this%plan%stage(1))
400 if (st%dst .ge. 0)
then
401 call cr_gather(u_d, this%sbuf_d, this%pack_send_d, st%nsw, strm)
410 call cr_gather(u_d, this%buf_d(st%dst_sel), this%pack_keep_d, &
420 integer,
intent(in) :: n
421 real(kind=rp),
dimension(n),
intent(inout) :: u
422 type(c_ptr),
intent(inout) :: strm
427 if (this%plan%nstage .eq. 0)
return
429 u_d = device_get_ptr(u)
434 do s = 2, this%plan%nstage
435 associate(st => this%plan%stage(s))
438 if (st%src .ge. 0)
then
439 this%nrreq = this%nrreq + 1
441 rp*st%nrw, st%src, this%tag, this%rreqs, this%nrreq)
443 if (st%src2 .ge. 0)
then
444 this%nrreq = this%nrreq + 1
446 rp*(st%nkw + st%nrw), rp*st%nr2w, st%src2, this%tag, &
447 this%rreqs, this%nrreq)
450 if (st%dst .ge. 0)
then
451 call cr_gather(this%buf_d(st%src_sel), this%sbuf_d, &
452 this%send_idx_d(s), st%nsw, strm)
453 call device_sync(strm)
456 this%tag, this%sreqs, 1)
461 if (.not. st%inplace)
then
462 call cr_gather(this%buf_d(st%src_sel), this%buf_d(st%dst_sel), &
463 this%keep_idx_d(s), st%nkw, strm)
468 call device_sync(strm)
472 call cr_scatter(u_d, op, this%buf_d(this%plan%final_sel), &
473 this%unpack_d, this%plan%nfinal, strm)
475 call device_sync(strm)
482 integer,
intent(in) :: tag, nc
484 if (nc .gt. gs_vec_nc)
then
485 call neko_error(
'gs_device_crystal: too many components in ' // &
494 if (this%plan%nstage .eq. 0)
return
496 associate(st => this%plan%stage(1))
497 if (st%src .ge. 0)
then
498 this%nrreq = this%nrreq + 1
500 rp*nc*st%nrw, st%src, tag, this%rreqs, this%nrreq)
502 if (st%src2 .ge. 0)
then
503 this%nrreq = this%nrreq + 1
505 rp*nc*(st%nkw + st%nrw), rp*nc*st%nr2w, st%src2, tag, &
506 this%rreqs, this%nrreq)
517 integer,
intent(in) :: n, nc
518 real(kind=rp),
dimension(nc*n),
intent(inout) :: u
519 integer,
intent(in) :: tag
520 type(c_ptr),
intent(inout) :: deps
521 type(c_ptr),
intent(inout) :: strm
524 if (this%plan%nstage .eq. 0)
return
526 u_d = device_get_ptr(u)
528 associate(st => this%plan%stage(1))
529 if (st%dst .ge. 0)
then
530 call cr_gather_vec(u_d, this%sbuf_v_d, this%pack_send_d, st%nsw, &
532 call device_sync(strm)
538 call cr_gather_vec(u_d, this%buf_v_d(st%dst_sel), this%pack_keep_d, &
548 integer,
intent(in) :: n, nc
549 real(kind=rp),
dimension(nc*n),
intent(inout) :: u
550 type(c_ptr),
intent(inout) :: strm
555 if (this%plan%nstage .eq. 0)
return
557 u_d = device_get_ptr(u)
562 do s = 2, this%plan%nstage
563 associate(st => this%plan%stage(s))
566 if (st%src .ge. 0)
then
567 this%nrreq = this%nrreq + 1
569 rp*nc*st%nrw, st%src, this%tag, this%rreqs, this%nrreq)
571 if (st%src2 .ge. 0)
then
572 this%nrreq = this%nrreq + 1
574 rp*nc*(st%nkw + st%nrw), rp*nc*st%nr2w, st%src2, &
575 this%tag, this%rreqs, this%nrreq)
581 if (st%dst .ge. 0)
then
582 call cr_gather(this%buf_v_d(st%src_sel), this%sbuf_v_d, &
583 this%send_idx_v_d(s), nc*st%nsw, strm)
584 call device_sync(strm)
587 this%tag, this%sreqs, 1)
590 if (.not. st%inplace)
then
591 call cr_gather(this%buf_v_d(st%src_sel), &
592 this%buf_v_d(st%dst_sel), this%keep_idx_v_d(s), &
598 call device_sync(strm)
603 this%unpack_d, this%plan%nfinal, nc, n, strm)
605 call device_sync(strm)
612 type(c_ptr),
intent(in) :: src_d, dst_d, idx_d
613 integer,
intent(in) :: n
614 type(c_ptr),
intent(inout) :: strm
623 call neko_error(
'gs_device_crystal: no backend')
631 type(c_ptr),
intent(in) :: src_d, dst_d, idx_d
632 integer,
intent(in) :: n, nc, ns
633 type(c_ptr),
intent(inout) :: strm
642 call neko_error(
'gs_device_crystal: no backend')
649 type(c_ptr),
intent(in) :: u_d, buf_d, idx_d
650 integer,
intent(in) :: op, n
651 type(c_ptr),
intent(inout) :: strm
660 call neko_error(
'gs_device_crystal: no backend')
667 type(c_ptr),
intent(in) :: u_d, buf_d, idx_d
668 integer,
intent(in) :: op, n, nc, ns
669 type(c_ptr),
intent(inout) :: strm
678 call neko_error(
'gs_device_crystal: no backend')
690 integer,
intent(in) :: nc
691 integer,
allocatable :: idx(:)
694 if (this%vec_nc .eq. nc)
return
699 do i = 2, this%plan%nstage
700 associate(st => this%plan%stage(i))
701 if (.not. st%inplace)
then
702 call cr_expand(st%keep_idx, st%nkw, nc, idx)
703 call cr_upload(this%keep_idx_v_d(i), idx, nc*st%nkw)
706 if (st%dst .ge. 0)
then
707 call cr_expand(st%send_idx, st%nsw, nc, idx)
708 call cr_upload(this%send_idx_v_d(i), idx, nc*st%nsw)
720 integer,
intent(in) :: idx(:)
721 integer,
intent(in) :: n, nc
722 integer,
allocatable,
intent(out) :: out(:)
725 allocate(out(
max(nc*n, 1)))
728 out(nc*(j-1) + c) = nc*(idx(j) - 1) + c
737 type(c_ptr),
intent(inout) :: ptr
738 integer,
intent(inout) :: idx(:)
739 integer,
intent(in) :: n
740 integer(c_size_t) :: sz
741 integer(c_int32_t) :: i4_dummy
743 if (c_associated(ptr))
call device_free(ptr)
748 sz = c_sizeof(i4_dummy) * n
749 call device_alloc(ptr, sz)
750 call device_memcpy(idx, ptr, n, host_to_device, sync = .true.)
756 type(c_ptr),
allocatable,
intent(inout) :: ptrs(:)
759 if (.not.
allocated(ptrs))
return
762 if (c_associated(ptrs(i)))
call device_free(ptrs(i))
771 integer,
intent(in) :: dof(:)
772 integer,
intent(out) :: out(:)
773 integer,
intent(in) :: n
774 type(htable_i4_t) :: doftable
775 integer :: j, dupe, key, val
781 call doftable%init(2*n)
784 if (doftable%get(key, dupe) .eq. 0)
then
785 if (out(dupe) .gt. 0) out(dupe) = -out(dupe)
790 call doftable%set(key, val)
void cuda_gs_unpack(real *u_d, int op, real *buf_d, int *dof_d, int offset, int n, cudaStream_t stream)
void cuda_gs_pack(void *u_d, void *buf_d, void *dof_d, int offset, int n, cudaStream_t stream)
void cuda_gs_pack_vec(void *u_d, void *buf_d, void *dof_d, int offset, int n, int nc, int ns, cudaStream_t stream)
void cuda_gs_unpack_vec(real *u_d, int op, real *buf_d, int *dof_d, int offset, int n, int nc, int ns, cudaStream_t stream)
Return the device pointer for an associated Fortran array.
Copy data between host and device (or device and device)
Synchronize a device or stream.
Device abstraction, common interface for various accelerators.
integer, parameter, public host_to_device
subroutine, public device_free(x_d)
Deallocate memory on the device.
subroutine, public device_alloc(x_d, s)
Allocate memory on the device.
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...
Routing plan for the crystal router gather-scatter comm. backends.
Defines GPU aware crystal router gather-scatter communication.
subroutine gs_device_crystal_init_vec(this)
Allocate the fused vector working and send buffers in device memory, sized for GS_VEC_NC components....
subroutine gs_device_crystal_free(this)
Deallocate crystal router based device communication.
subroutine gs_device_crystal_nbwait_vec(this, u, n, nc, op, strm)
Drive the remaining routing stages and reduce what is delivered into the shared vector,...
subroutine cr_gather(src_d, dst_d, idx_d, n, strm)
Gather n words of src into dst through the 1-based index list idx_d, i.e. dst(j) = src(idx(j))
subroutine gs_device_crystal_nbrecv(this, tag)
Post the receives of the first routing stage.
subroutine cr_vec_index(this, nc)
Build the per-stage index lists of the fused vector exchange, which address the same words as the sca...
subroutine gs_device_crystal_nbrecv_vec(this, tag, nc)
Post the receives of the first routing stage, fused nc-component.
subroutine cr_upload(ptr, idx, n)
Copy the first n entries of an index list to the device, leaving ptr null when there are none.
subroutine cr_gather_vec(src_d, dst_d, idx_d, n, nc, ns, strm)
Gather n positions of the component-outer src (stride ns) into the interleaved dst.
subroutine cr_scatter(u_d, op, buf_d, idx_d, n, strm)
Reduce n delivered words into the shared vector under op.
subroutine gs_device_crystal_nbwait(this, u, n, op, strm)
Drive the remaining routing stages and reduce what is delivered into the shared vector.
subroutine cr_mark_dupes(dof, out, n)
Copy dof into out, negating every index that appears more than once so that the unpack kernel reduces...
subroutine gs_device_crystal_init(this, send_pe, recv_pe)
Initialise crystal router based device communication See gs_comm.f90 for details.
subroutine cr_scatter_vec(u_d, op, buf_d, idx_d, n, nc, ns, strm)
Reduce n delivered positions into the component-outer shared vector.
subroutine gs_device_crystal_nbsend(this, u, n, tag, deps, strm)
Pack the shared vector and post the send of the first routing stage.
subroutine cr_free_ptrs(ptrs)
Release a list of device pointers, leaving them null.
subroutine gs_device_crystal_nbsend_vec(this, u, n, nc, tag, deps, strm)
Pack the shared vector and post the send of the first routing stage, fused nc-component.
subroutine cr_expand(idx, n, nc, out)
Spell out the components of the 1-based index list idx over nc.
Implements a hash table ADT.
integer, parameter, public c_rp
integer, parameter, public rp
Global precision used in computations.
Implements a dynamic stack ADT.
Gather-scatter communication method.
The full routing plan for one gather-scatter schedule.
Gather-scatter communication using a crystal router on the device.
Integer based hash table.