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
106 bind(c, name =
'hip_gs_pack')
107 use,
intrinsic :: iso_c_binding
109 integer(c_int),
value :: n, offset
110 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
116 bind(c, name =
'hip_gs_unpack')
117 use,
intrinsic :: iso_c_binding
119 integer(c_int),
value :: op, offset, n
120 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
126 bind(c, name =
'hip_gs_pack_vec')
127 use,
intrinsic :: iso_c_binding
129 integer(c_int),
value :: offset, n, nc, ns
130 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
136 stream) bind(c, name = 'hip_gs_unpack_vec')
137 use,
intrinsic :: iso_c_binding
139 integer(c_int),
value :: op, offset, n, nc, ns
140 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
145 subroutine cuda_gs_pack(u_d, buf_d, dof_d, offset, n, stream) &
146 bind(c, name =
'cuda_gs_pack')
147 use,
intrinsic :: iso_c_binding
149 integer(c_int),
value :: n, offset
150 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
155 subroutine cuda_gs_unpack(u_d, op, buf_d, dof_d, offset, n, stream) &
156 bind(c, name =
'cuda_gs_unpack')
157 use,
intrinsic :: iso_c_binding
159 integer(c_int),
value :: op, offset, n
160 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
166 bind(c, name =
'cuda_gs_pack_vec')
167 use,
intrinsic :: iso_c_binding
169 integer(c_int),
value :: offset, n, nc, ns
170 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
176 stream) bind(c, name = 'cuda_gs_unpack_vec')
177 use,
intrinsic :: iso_c_binding
179 integer(c_int),
value :: op, offset, n, nc, ns
180 type(c_ptr),
value :: u_d, buf_d, dof_d, stream
187 bind(c, name =
'device_mpi_init_reqs')
188 use,
intrinsic :: iso_c_binding
190 integer(c_int),
value :: n
197 bind(c, name =
'device_mpi_free_reqs')
198 use,
intrinsic :: iso_c_binding
206 bind(c, name =
'device_mpi_isend')
207 use,
intrinsic :: iso_c_binding
209 integer(c_int),
value :: offset, nbytes, rank, tag, i
210 type(c_ptr),
value :: buf_d, reqs
216 bind(c, name =
'device_mpi_irecv')
217 use,
intrinsic :: iso_c_binding
219 integer(c_int),
value :: offset, nbytes, rank, tag, i
220 type(c_ptr),
value :: buf_d, reqs
226 bind(c, name =
'device_mpi_waitall')
227 use,
intrinsic :: iso_c_binding
229 integer(c_int),
value :: n
230 type(c_ptr),
value :: reqs
242 integer,
allocatable :: dofs(:)
244 integer(c_size_t) :: sz
245 real(c_rp) :: rp_dummy
247 call this%init_order(send_pe, recv_pe)
249 call this%plan%init(this%send_pe, this%recv_pe, this%send_dof, &
255 sz = c_sizeof(rp_dummy) * this%plan%nwrk
258 sz = c_sizeof(rp_dummy) * this%plan%nsmax
261 sz = c_sizeof(rp_dummy) *
gs_vec_nc * this%plan%nwrk
264 sz = c_sizeof(rp_dummy) *
gs_vec_nc * this%plan%nsmax
268 if (this%plan%nstage .gt. 0)
then
269 call cr_upload(this%pack_keep_d, this%plan%pack_keep_dof, &
270 this%plan%stage(1)%nkw)
271 call cr_upload(this%pack_send_d, this%plan%pack_send_dof, &
272 this%plan%stage(1)%nsw)
277 allocate(dofs(
max(this%plan%nfinal, 1)))
278 call cr_mark_dupes(this%plan%unpack_dof, dofs, this%plan%nfinal)
279 call cr_upload(this%unpack_d, dofs, this%plan%nfinal)
282 nst =
max(this%plan%nstage, 1)
283 allocate(this%keep_idx_d(nst), this%send_idx_d(nst))
284 allocate(this%keep_idx_v_d(nst), this%send_idx_v_d(nst))
285 this%keep_idx_d = c_null_ptr
286 this%send_idx_d = c_null_ptr
287 this%keep_idx_v_d = c_null_ptr
288 this%send_idx_v_d = c_null_ptr
291 do i = 2, this%plan%nstage
292 associate(st => this%plan%stage(i))
293 if (.not. st%inplace)
then
294 call cr_upload(this%keep_idx_d(i), st%keep_idx, st%nkw)
296 if (st%dst .ge. 0)
then
297 call cr_upload(this%send_idx_d(i), st%send_idx, st%nsw)
302 this%vec_supported = .true.
315 if (c_associated(this%buf_d(i)))
call device_free(this%buf_d(i))
316 if (c_associated(this%buf_v_d(i)))
call device_free(this%buf_v_d(i))
318 if (c_associated(this%sbuf_d))
call device_free(this%sbuf_d)
319 if (c_associated(this%sbuf_v_d))
call device_free(this%sbuf_v_d)
321 if (c_associated(this%pack_keep_d))
call device_free(this%pack_keep_d)
322 if (c_associated(this%pack_send_d))
call device_free(this%pack_send_d)
323 if (c_associated(this%unpack_d))
call device_free(this%unpack_d)
330 if (
allocated(this%keep_idx_d))
deallocate(this%keep_idx_d)
331 if (
allocated(this%send_idx_d))
deallocate(this%send_idx_d)
332 if (
allocated(this%keep_idx_v_d))
deallocate(this%keep_idx_v_d)
333 if (
allocated(this%send_idx_v_d))
deallocate(this%send_idx_v_d)
337 call this%plan%free()
339 call this%free_order()
340 call this%free_dofs()
347 integer,
intent(in) :: tag
352 if (this%plan%nstage .eq. 0)
return
354 associate(st => this%plan%stage(1))
355 if (st%src .ge. 0)
then
356 this%nrreq = this%nrreq + 1
358 rp*st%nrw, st%src, tag, this%rreqs, this%nrreq)
360 if (st%src2 .ge. 0)
then
361 this%nrreq = this%nrreq + 1
363 rp*(st%nkw + st%nrw),
rp*st%nr2w, st%src2, tag, &
364 this%rreqs, this%nrreq)
373 integer,
intent(in) :: n
374 real(kind=
rp),
dimension(n),
intent(inout) :: u
375 integer,
intent(in) :: tag
376 type(c_ptr),
intent(inout) :: deps
377 type(c_ptr),
intent(inout) :: strm
380 if (this%plan%nstage .eq. 0)
return
384 associate(st => this%plan%stage(1))
385 if (st%dst .ge. 0)
then
386 call cr_gather(u_d, this%sbuf_d, this%pack_send_d, st%nsw, strm)
395 call cr_gather(u_d, this%buf_d(st%dst_sel), this%pack_keep_d, &
405 integer,
intent(in) :: n
406 real(kind=rp),
dimension(n),
intent(inout) :: u
407 type(c_ptr),
intent(inout) :: strm
412 if (this%plan%nstage .eq. 0)
return
414 u_d = device_get_ptr(u)
419 do s = 2, this%plan%nstage
420 associate(st => this%plan%stage(s))
423 if (st%src .ge. 0)
then
424 this%nrreq = this%nrreq + 1
426 rp*st%nrw, st%src, this%tag, this%rreqs, this%nrreq)
428 if (st%src2 .ge. 0)
then
429 this%nrreq = this%nrreq + 1
431 rp*(st%nkw + st%nrw), rp*st%nr2w, st%src2, this%tag, &
432 this%rreqs, this%nrreq)
435 if (st%dst .ge. 0)
then
436 call cr_gather(this%buf_d(st%src_sel), this%sbuf_d, &
437 this%send_idx_d(s), st%nsw, strm)
438 call device_sync(strm)
441 this%tag, this%sreqs, 1)
446 if (.not. st%inplace)
then
447 call cr_gather(this%buf_d(st%src_sel), this%buf_d(st%dst_sel), &
448 this%keep_idx_d(s), st%nkw, strm)
453 call device_sync(strm)
457 call cr_scatter(u_d, op, this%buf_d(this%plan%final_sel), &
458 this%unpack_d, this%plan%nfinal, strm)
460 call device_sync(strm)
467 integer,
intent(in) :: tag, nc
469 if (nc .gt. gs_vec_nc)
then
470 call neko_error(
'gs_device_crystal: too many components in ' // &
479 if (this%plan%nstage .eq. 0)
return
481 associate(st => this%plan%stage(1))
482 if (st%src .ge. 0)
then
483 this%nrreq = this%nrreq + 1
485 rp*nc*st%nrw, st%src, tag, this%rreqs, this%nrreq)
487 if (st%src2 .ge. 0)
then
488 this%nrreq = this%nrreq + 1
490 rp*nc*(st%nkw + st%nrw), rp*nc*st%nr2w, st%src2, tag, &
491 this%rreqs, this%nrreq)
502 integer,
intent(in) :: n, nc
503 real(kind=rp),
dimension(nc*n),
intent(inout) :: u
504 integer,
intent(in) :: tag
505 type(c_ptr),
intent(inout) :: deps
506 type(c_ptr),
intent(inout) :: strm
509 if (this%plan%nstage .eq. 0)
return
511 u_d = device_get_ptr(u)
513 associate(st => this%plan%stage(1))
514 if (st%dst .ge. 0)
then
515 call cr_gather_vec(u_d, this%sbuf_v_d, this%pack_send_d, st%nsw, &
517 call device_sync(strm)
523 call cr_gather_vec(u_d, this%buf_v_d(st%dst_sel), this%pack_keep_d, &
533 integer,
intent(in) :: n, nc
534 real(kind=rp),
dimension(nc*n),
intent(inout) :: u
535 type(c_ptr),
intent(inout) :: strm
540 if (this%plan%nstage .eq. 0)
return
542 u_d = device_get_ptr(u)
547 do s = 2, this%plan%nstage
548 associate(st => this%plan%stage(s))
551 if (st%src .ge. 0)
then
552 this%nrreq = this%nrreq + 1
554 rp*nc*st%nrw, st%src, this%tag, this%rreqs, this%nrreq)
556 if (st%src2 .ge. 0)
then
557 this%nrreq = this%nrreq + 1
559 rp*nc*(st%nkw + st%nrw), rp*nc*st%nr2w, st%src2, &
560 this%tag, this%rreqs, this%nrreq)
566 if (st%dst .ge. 0)
then
567 call cr_gather(this%buf_v_d(st%src_sel), this%sbuf_v_d, &
568 this%send_idx_v_d(s), nc*st%nsw, strm)
569 call device_sync(strm)
572 this%tag, this%sreqs, 1)
575 if (.not. st%inplace)
then
576 call cr_gather(this%buf_v_d(st%src_sel), &
577 this%buf_v_d(st%dst_sel), this%keep_idx_v_d(s), &
583 call device_sync(strm)
588 this%unpack_d, this%plan%nfinal, nc, n, strm)
590 call device_sync(strm)
597 type(c_ptr),
intent(in) :: src_d, dst_d, idx_d
598 integer,
intent(in) :: n
599 type(c_ptr),
intent(inout) :: strm
608 call neko_error(
'gs_device_crystal: no backend')
616 type(c_ptr),
intent(in) :: src_d, dst_d, idx_d
617 integer,
intent(in) :: n, nc, ns
618 type(c_ptr),
intent(inout) :: strm
627 call neko_error(
'gs_device_crystal: no backend')
634 type(c_ptr),
intent(in) :: u_d, buf_d, idx_d
635 integer,
intent(in) :: op, n
636 type(c_ptr),
intent(inout) :: strm
645 call neko_error(
'gs_device_crystal: no backend')
652 type(c_ptr),
intent(in) :: u_d, buf_d, idx_d
653 integer,
intent(in) :: op, n, nc, ns
654 type(c_ptr),
intent(inout) :: strm
663 call neko_error(
'gs_device_crystal: no backend')
675 integer,
intent(in) :: nc
676 integer,
allocatable :: idx(:)
679 if (this%vec_nc .eq. nc)
return
684 do i = 2, this%plan%nstage
685 associate(st => this%plan%stage(i))
686 if (.not. st%inplace)
then
687 call cr_expand(st%keep_idx, st%nkw, nc, idx)
688 call cr_upload(this%keep_idx_v_d(i), idx, nc*st%nkw)
691 if (st%dst .ge. 0)
then
692 call cr_expand(st%send_idx, st%nsw, nc, idx)
693 call cr_upload(this%send_idx_v_d(i), idx, nc*st%nsw)
705 integer,
intent(in) :: idx(:)
706 integer,
intent(in) :: n, nc
707 integer,
allocatable,
intent(out) :: out(:)
710 allocate(out(
max(nc*n, 1)))
713 out(nc*(j-1) + c) = nc*(idx(j) - 1) + c
722 type(c_ptr),
intent(inout) :: ptr
723 integer,
intent(inout) :: idx(:)
724 integer,
intent(in) :: n
725 integer(c_size_t) :: sz
726 integer(c_int32_t) :: i4_dummy
728 if (c_associated(ptr))
call device_free(ptr)
733 sz = c_sizeof(i4_dummy) * n
734 call device_alloc(ptr, sz)
735 call device_memcpy(idx, ptr, n, host_to_device, sync = .true.)
741 type(c_ptr),
allocatable,
intent(inout) :: ptrs(:)
744 if (.not.
allocated(ptrs))
return
747 if (c_associated(ptrs(i)))
call device_free(ptrs(i))
756 integer,
intent(in) :: dof(:)
757 integer,
intent(out) :: out(:)
758 integer,
intent(in) :: n
759 type(htable_i4_t) :: doftable
760 integer :: j, dupe, key, val
766 call doftable%init(2*n)
769 if (doftable%get(key, dupe) .eq. 0)
then
770 if (out(dupe) .gt. 0) out(dupe) = -out(dupe)
775 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_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.