Neko 1.99.5
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
gs_device_mpi.F90
Go to the documentation of this file.
1! Copyright (c) 2020-2025, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
35 use num_types, only : rp, c_rp
36 use gs_comm, only : gs_comm_t, gs_vec_nc
37 use stack, only : stack_i4_t
38 use comm, only : pe_size, pe_rank
39 use htable, only : htable_i4_t
45 use utils, only : neko_error
46 use, intrinsic :: iso_c_binding, only : c_sizeof, c_int32_t, &
47 c_ptr, c_null_ptr, c_size_t, c_associated
48 implicit none
49 private
50
52 type, private :: gs_device_mpi_buf_t
53 integer, allocatable :: ndofs(:)
54 integer, allocatable :: offset(:)
55 integer :: total
56 type(c_ptr) :: reqs = c_null_ptr
57 type(c_ptr) :: buf_d = c_null_ptr
58 type(c_ptr) :: buf_v_d = c_null_ptr
59 type(c_ptr) :: dof_d = c_null_ptr
60 contains
61 procedure, pass(this) :: init => gs_device_mpi_buf_init
62 procedure, pass(this) :: free => gs_device_mpi_buf_free
63 end type gs_device_mpi_buf_t
64
67 type, public, extends(gs_comm_t) :: gs_device_mpi_t
68 type(gs_device_mpi_buf_t) :: send_buf
69 type(gs_device_mpi_buf_t) :: recv_buf
70 type(c_ptr), allocatable :: stream(:)
71 type(c_ptr), allocatable :: event(:)
72 integer :: nb_strtgy
73 type(c_ptr) :: send_event = c_null_ptr
74 contains
75 procedure, pass(this) :: init => gs_device_mpi_init
76 procedure, pass(this) :: free => gs_device_mpi_free
77 procedure, pass(this) :: nbsend => gs_device_mpi_nbsend
78 procedure, pass(this) :: nbrecv => gs_device_mpi_nbrecv
79 procedure, pass(this) :: nbwait => gs_device_mpi_nbwait
80 procedure, pass(this) :: nbsend_vec => gs_device_mpi_nbsend_vec
81 procedure, pass(this) :: nbrecv_vec => gs_device_mpi_nbrecv_vec
82 procedure, pass(this) :: nbwait_vec => gs_device_mpi_nbwait_vec
83 end type gs_device_mpi_t
84
85#ifdef HAVE_HIP
86 interface
87 subroutine hip_gs_pack(u_d, buf_d, dof_d, offset, n, stream) &
88 bind(c, name = 'hip_gs_pack')
89 use, intrinsic :: iso_c_binding
90 implicit none
91 integer(c_int), value :: n, offset
92 type(c_ptr), value :: u_d, buf_d, dof_d, stream
93 end subroutine hip_gs_pack
94 end interface
95
96 interface
97 subroutine hip_gs_unpack(u_d, op, buf_d, dof_d, offset, n, stream) &
98 bind(c, name = 'hip_gs_unpack')
99 use, intrinsic :: iso_c_binding
100 implicit none
101 integer(c_int), value :: op, offset, n
102 type(c_ptr), value :: u_d, buf_d, dof_d, stream
103 end subroutine hip_gs_unpack
104 end interface
105
106 interface
107 subroutine hip_gs_pack_vec(u_d, buf_d, dof_d, offset, n, nc, ns, stream) &
108 bind(c, name = 'hip_gs_pack_vec')
109 use, intrinsic :: iso_c_binding
110 implicit none
111 integer(c_int), value :: offset, n, nc, ns
112 type(c_ptr), value :: u_d, buf_d, dof_d, stream
113 end subroutine hip_gs_pack_vec
114 end interface
115
116 interface
117 subroutine hip_gs_unpack_vec(u_d, op, buf_d, dof_d, offset, n, nc, ns, &
118 stream) bind(c, name = 'hip_gs_unpack_vec')
119 use, intrinsic :: iso_c_binding
120 implicit none
121 integer(c_int), value :: op, offset, n, nc, ns
122 type(c_ptr), value :: u_d, buf_d, dof_d, stream
123 end subroutine hip_gs_unpack_vec
124 end interface
125#elif HAVE_CUDA
126 interface
127 subroutine cuda_gs_pack(u_d, buf_d, dof_d, offset, n, stream) &
128 bind(c, name = 'cuda_gs_pack')
129 use, intrinsic :: iso_c_binding
130 implicit none
131 integer(c_int), value :: n, offset
132 type(c_ptr), value :: u_d, buf_d, dof_d, stream
133 end subroutine cuda_gs_pack
134 end interface
135
136 interface
137 subroutine cuda_gs_unpack(u_d, op, buf_d, dof_d, offset, n, stream) &
138 bind(c, name = 'cuda_gs_unpack')
139 use, intrinsic :: iso_c_binding
140 implicit none
141 integer(c_int), value :: op, offset, n
142 type(c_ptr), value :: u_d, buf_d, dof_d, stream
143 end subroutine cuda_gs_unpack
144 end interface
145
146 interface
147 subroutine cuda_gs_pack_vec(u_d, buf_d, dof_d, offset, n, nc, ns, stream) &
148 bind(c, name = 'cuda_gs_pack_vec')
149 use, intrinsic :: iso_c_binding
150 implicit none
151 integer(c_int), value :: offset, n, nc, ns
152 type(c_ptr), value :: u_d, buf_d, dof_d, stream
153 end subroutine cuda_gs_pack_vec
154 end interface
155
156 interface
157 subroutine cuda_gs_unpack_vec(u_d, op, buf_d, dof_d, offset, n, nc, ns, &
158 stream) bind(c, name = 'cuda_gs_unpack_vec')
159 use, intrinsic :: iso_c_binding
160 implicit none
161 integer(c_int), value :: op, offset, n, nc, ns
162 type(c_ptr), value :: u_d, buf_d, dof_d, stream
163 end subroutine cuda_gs_unpack_vec
164 end interface
165#endif
166
167 interface
168 subroutine device_mpi_init_reqs(n, reqs) &
169 bind(c, name = 'device_mpi_init_reqs')
170 use, intrinsic :: iso_c_binding
171 implicit none
172 integer(c_int), value :: n
173 type(c_ptr) :: reqs
174 end subroutine device_mpi_init_reqs
175 end interface
176
177 interface
178 subroutine device_mpi_free_reqs(reqs) &
179 bind(c, name = 'device_mpi_free_reqs')
180 use, intrinsic :: iso_c_binding
181 implicit none
182 type(c_ptr) :: reqs
183 end subroutine device_mpi_free_reqs
184 end interface
185
186 interface
187 subroutine device_mpi_isend(buf_d, offset, nbytes, rank, tag, reqs, i) &
188 bind(c, name = 'device_mpi_isend')
189 use, intrinsic :: iso_c_binding
190 implicit none
191 integer(c_int), value :: offset, nbytes, rank, tag, i
192 type(c_ptr), value :: buf_d, reqs
193 end subroutine device_mpi_isend
194 end interface
195
196 interface
197 subroutine device_mpi_irecv(buf_d, offset, nbytes, rank, tag, reqs, i) &
198 bind(c, name = 'device_mpi_irecv')
199 use, intrinsic :: iso_c_binding
200 implicit none
201 integer(c_int), value :: offset, nbytes, rank, tag, i
202 type(c_ptr), value :: buf_d, reqs
203 end subroutine device_mpi_irecv
204 end interface
205
206 interface
207 integer(c_int) function device_mpi_test(reqs, i) &
208 bind(c, name = 'device_mpi_test')
209 use, intrinsic :: iso_c_binding
210 implicit none
211 integer(c_int), value :: i
212 type(c_ptr), value :: reqs
213 end function device_mpi_test
214 end interface
215
216 interface
217 subroutine device_mpi_waitall(n, reqs) &
218 bind(c, name = 'device_mpi_waitall')
219 use, intrinsic :: iso_c_binding
220 implicit none
221 integer(c_int), value :: n
222 type(c_ptr), value :: reqs
223 end subroutine device_mpi_waitall
224 end interface
225
226 interface
227 integer(c_int) function device_mpi_waitany(n, reqs, i) &
228 bind(c, name = 'device_mpi_waitany')
229 use, intrinsic :: iso_c_binding
230 implicit none
231 integer(c_int), value :: n
232 integer(c_int) :: i
233 type(c_ptr), value :: reqs
234 end function device_mpi_waitany
235 end interface
236
237contains
238
239 subroutine gs_device_mpi_buf_init(this, pe_order, dof_stack, mark_dupes)
240 class(gs_device_mpi_buf_t), intent(inout) :: this
241 integer, allocatable, intent(inout) :: pe_order(:)
242 type(stack_i4_t), allocatable, intent(inout) :: dof_stack(:)
243 logical, intent(in) :: mark_dupes
244 integer, allocatable :: dofs(:)
245 integer :: i, j, total
246 integer(c_size_t) :: sz
247 type(htable_i4_t) :: doftable
248 integer :: dupe, marked, k
249 real(c_rp) :: rp_dummy
250 integer(c_int32_t) :: i4_dummy
251
252 call device_mpi_init_reqs(size(pe_order), this%reqs)
253
254 allocate(this%ndofs(size(pe_order)))
255 allocate(this%offset(size(pe_order)))
256
257 total = 0
258 do i = 1, size(pe_order)
259 this%ndofs(i) = dof_stack(pe_order(i))%size()
260 this%offset(i) = total
261 total = total + this%ndofs(i)
262 end do
263
264 this%total = total
265
266 sz = c_sizeof(rp_dummy) * total
267 call device_alloc(this%buf_d, sz)
268 call device_memset(this%buf_d, 0, sz, sync = .true.)
269
270 ! Fused vector buffer, sized for up to GS_VEC_NC components.
271 sz = c_sizeof(rp_dummy) * gs_vec_nc * total
272 call device_alloc(this%buf_v_d, sz)
273 call device_memset(this%buf_v_d, 0, sz, sync = .true.)
274
275 sz = c_sizeof(i4_dummy) * total
276 call device_alloc(this%dof_d, sz)
277
278 if (mark_dupes) call doftable%init(2*total)
279 allocate(dofs(total))
280
281 ! Copy from dof_stack into dofs, optionally marking duplicates with doftable
282 marked = 0
283 do i = 1, size(pe_order)
284 ! %array() breaks on cray
285 select type (arr => dof_stack(pe_order(i))%data)
286 type is (integer)
287 do j = 1, this%ndofs(i)
288 k = this%offset(i) + j
289 if (mark_dupes) then
290 if (doftable%get(arr(j), dupe) .eq. 0) then
291 if (dofs(dupe) .gt. 0) then
292 dofs(dupe) = -dofs(dupe)
293 marked = marked + 1
294 end if
295 dofs(k) = -arr(j)
296 marked = marked + 1
297 else
298 call doftable%set(arr(j), k)
299 dofs(k) = arr(j)
300 end if
301 else
302 dofs(k) = arr(j)
303 end if
304 end do
305 end select
306 end do
307 call device_memcpy(dofs, this%dof_d, total, host_to_device, &
308 sync = .true.)
309 ! Syncing here prevents the memory in dofs to accidently be corrupted
310 ! while this memcpy is happening.
311 ! This might be happening in many other places as well. Karp 4/6-25
312
313 deallocate(dofs)
314 call doftable%free()
315
316 end subroutine gs_device_mpi_buf_init
317
318 subroutine gs_device_mpi_buf_free(this)
319 class(gs_device_mpi_buf_t), intent(inout) :: this
320
321 if (c_associated(this%reqs)) call device_mpi_free_reqs(this%reqs)
322
323 if (allocated(this%ndofs)) deallocate(this%ndofs)
324 if (allocated(this%offset)) deallocate(this%offset)
325
326 if (c_associated(this%buf_d)) call device_free(this%buf_d)
327 if (c_associated(this%buf_v_d)) call device_free(this%buf_v_d)
328 if (c_associated(this%dof_d)) call device_free(this%dof_d)
329 end subroutine gs_device_mpi_buf_free
330
332 subroutine gs_device_mpi_init(this, send_pe, recv_pe)
333 class(gs_device_mpi_t), intent(inout) :: this
334 type(stack_i4_t), intent(inout) :: send_pe
335 type(stack_i4_t), intent(inout) :: recv_pe
336 integer :: i, nstrm
337
338 call this%init_order(send_pe, recv_pe)
339
340 call this%send_buf%init(this%send_pe, this%send_dof, .false.)
341 call this%recv_buf%init(this%recv_pe, this%recv_dof, .true.)
342
343#if defined(HAVE_HIP) || defined(HAVE_CUDA)
344 ! Create a set of non-blocking streams. The per-peer streams and events
345 ! are indexed over both send_pe (pack) and recv_pe (unpack, sync), so
346 ! size them for the larger of the two peer lists.
347 nstrm = max(size(this%send_pe), size(this%recv_pe))
348 allocate(this%stream(nstrm))
349 do i = 1, nstrm
350 call device_stream_create_with_priority(this%stream(i), 1, &
352 end do
353
354 allocate(this%event(nstrm))
355 do i = 1, nstrm
356 call device_event_create(this%event(i), 2)
357 end do
358#endif
359
360
361 this%nb_strtgy = 0
362
363 this%vec_supported = .true.
364
365 end subroutine gs_device_mpi_init
366
368 subroutine gs_device_mpi_free(this)
369 class(gs_device_mpi_t), intent(inout) :: this
370 integer :: i
371
372 call this%send_buf%free()
373 call this%recv_buf%free()
374
375 call this%free_order()
376 call this%free_dofs()
377
378#if defined(HAVE_HIP) || defined(HAVE_CUDA)
379 if (allocated(this%stream)) then
380 do i = 1, size(this%stream)
381 call device_stream_destroy(this%stream(i))
382 end do
383 deallocate(this%stream)
384 end if
385#endif
386
387 end subroutine gs_device_mpi_free
388
390 subroutine gs_device_mpi_nbsend(this, u, n, tag, deps, strm)
391 class(gs_device_mpi_t), intent(inout) :: this
392 integer, intent(in) :: n
393 real(kind=rp), dimension(n), intent(inout) :: u
394 integer, intent(in) :: tag
395 type(c_ptr), intent(inout) :: deps
396 type(c_ptr), intent(inout) :: strm
397 integer :: i
398 type(c_ptr) :: u_d
399
400 u_d = device_get_ptr(u)
401
402 if (iand(this%nb_strtgy, 1) .eq. 0) then
403
404#ifdef HAVE_HIP
405 call hip_gs_pack(u_d, &
406 this%send_buf%buf_d, &
407 this%send_buf%dof_d, &
408 0, this%send_buf%total, &
409 strm)
410#elif HAVE_CUDA
411 call cuda_gs_pack(u_d, &
412 this%send_buf%buf_d, &
413 this%send_buf%dof_d, &
414 0, this%send_buf%total, &
415 strm)
416#else
417 call neko_error('gs_device_mpi: no backend')
418#endif
419
420 call device_sync(strm)
421
422 do i = 1, size(this%send_pe)
423 call device_mpi_isend(this%send_buf%buf_d, &
424 rp*this%send_buf%offset(i), &
425 rp*this%send_buf%ndofs(i), this%send_pe(i), tag, &
426 this%send_buf%reqs, i)
427 end do
428
429 else
430
431 do i = 1, size(this%send_pe)
432 call device_stream_wait_event(this%stream(i), deps, 0)
433#ifdef HAVE_HIP
434 call hip_gs_pack(u_d, &
435 this%send_buf%buf_d, &
436 this%send_buf%dof_d, &
437 this%send_buf%offset(i), &
438 this%send_buf%ndofs(i), &
439 this%stream(i))
440#elif HAVE_CUDA
441 call cuda_gs_pack(u_d, &
442 this%send_buf%buf_d, &
443 this%send_buf%dof_d, &
444 this%send_buf%offset(i), &
445 this%send_buf%ndofs(i), &
446 this%stream(i))
447#else
448 call neko_error('gs_device_mpi: no backend')
449#endif
450 end do
451
452 ! Consider adding a poll loop here once we have device_query in place
453 do i = 1, size(this%send_pe)
454 call device_sync(this%stream(i))
455 call device_mpi_isend(this%send_buf%buf_d, &
456 rp*this%send_buf%offset(i), &
457 rp*this%send_buf%ndofs(i), this%send_pe(i), tag, &
458 this%send_buf%reqs, i)
459 end do
460 end if
461
462 end subroutine gs_device_mpi_nbsend
463
465 subroutine gs_device_mpi_nbrecv(this, tag)
466 class(gs_device_mpi_t), intent(inout) :: this
467 integer, intent(in) :: tag
468 integer :: i
469
470 do i = 1, size(this%recv_pe)
471 call device_mpi_irecv(this%recv_buf%buf_d, rp*this%recv_buf%offset(i), &
472 rp*this%recv_buf%ndofs(i), this%recv_pe(i), tag, &
473 this%recv_buf%reqs, i)
474 end do
475
476 end subroutine gs_device_mpi_nbrecv
477
479 subroutine gs_device_mpi_nbwait(this, u, n, op, strm)
480 class(gs_device_mpi_t), intent(inout) :: this
481 integer, intent(in) :: n
482 real(kind=rp), dimension(n), intent(inout) :: u
483 type(c_ptr), intent(inout) :: strm
484 integer :: op, done_req, i
485 type(c_ptr) :: u_d
486
487 u_d = device_get_ptr(u)
488
489 if (iand(this%nb_strtgy, 2) .eq. 0) then
490 call device_mpi_waitall(size(this%recv_pe), this%recv_buf%reqs)
491
492#ifdef HAVE_HIP
493 call hip_gs_unpack(u_d, op, &
494 this%recv_buf%buf_d, &
495 this%recv_buf%dof_d, &
496 0, this%recv_buf%total, &
497 strm)
498#elif HAVE_CUDA
499 call cuda_gs_unpack(u_d, op, &
500 this%recv_buf%buf_d, &
501 this%recv_buf%dof_d, &
502 0, this%recv_buf%total, &
503 strm)
504#else
505 call neko_error('gs_device_mpi: no backend')
506#endif
507
508 call device_mpi_waitall(size(this%send_pe), this%send_buf%reqs)
509
510 ! Syncing here seems to prevent some race condition
511 call device_sync(strm)
512
513 else
514
515 do while (device_mpi_waitany(size(this%recv_pe), &
516 this%recv_buf%reqs, done_req) .ne. 0)
517
518#ifdef HAVE_HIP
519 call hip_gs_unpack(u_d, op, &
520 this%recv_buf%buf_d, &
521 this%recv_buf%dof_d, &
522 this%recv_buf%offset(done_req), &
523 this%recv_buf%ndofs(done_req), &
524 this%stream(done_req))
525#elif HAVE_CUDA
526 call cuda_gs_unpack(u_d, op, &
527 this%recv_buf%buf_d, &
528 this%recv_buf%dof_d, &
529 this%recv_buf%offset(done_req), &
530 this%recv_buf%ndofs(done_req), &
531 this%stream(done_req))
532#else
533 call neko_error('gs_device_mpi: no backend')
534#endif
535 call device_event_record(this%event(done_req), this%stream(done_req))
536 end do
537
538 call device_mpi_waitall(size(this%send_pe), this%send_buf%reqs)
539
540 ! Sync non-blocking streams
541 do done_req = 1, size(this%recv_pe)
542 call device_stream_wait_event(strm, &
543 this%event(done_req), 0)
544 end do
545
546 end if
547
548 end subroutine gs_device_mpi_nbwait
549
553 subroutine gs_device_mpi_nbsend_vec(this, u, n, nc, tag, deps, strm)
554 class(gs_device_mpi_t), intent(inout) :: this
555 integer, intent(in) :: n, nc
556 real(kind=rp), dimension(nc*n), intent(inout) :: u
557 integer, intent(in) :: tag
558 type(c_ptr), intent(inout) :: deps
559 type(c_ptr), intent(inout) :: strm
560 integer :: i
561 type(c_ptr) :: u_d
562
563 u_d = device_get_ptr(u)
564
565#ifdef HAVE_HIP
566 call hip_gs_pack_vec(u_d, this%send_buf%buf_v_d, this%send_buf%dof_d, &
567 0, this%send_buf%total, nc, n, strm)
568#elif HAVE_CUDA
569 call cuda_gs_pack_vec(u_d, this%send_buf%buf_v_d, this%send_buf%dof_d, &
570 0, this%send_buf%total, nc, n, strm)
571#else
572 call neko_error('gs_device_mpi: no backend')
573#endif
574
575 call device_sync(strm)
576
577 do i = 1, size(this%send_pe)
578 call device_mpi_isend(this%send_buf%buf_v_d, &
579 rp*nc*this%send_buf%offset(i), &
580 rp*nc*this%send_buf%ndofs(i), this%send_pe(i), tag, &
581 this%send_buf%reqs, i)
582 end do
583
584 end subroutine gs_device_mpi_nbsend_vec
585
587 subroutine gs_device_mpi_nbrecv_vec(this, tag, nc)
588 class(gs_device_mpi_t), intent(inout) :: this
589 integer, intent(in) :: tag, nc
590 integer :: i
591
592 do i = 1, size(this%recv_pe)
593 call device_mpi_irecv(this%recv_buf%buf_v_d, &
594 rp*nc*this%recv_buf%offset(i), &
595 rp*nc*this%recv_buf%ndofs(i), this%recv_pe(i), tag, &
596 this%recv_buf%reqs, i)
597 end do
598
599 end subroutine gs_device_mpi_nbrecv_vec
600
602 subroutine gs_device_mpi_nbwait_vec(this, u, n, nc, op, strm)
603 class(gs_device_mpi_t), intent(inout) :: this
604 integer, intent(in) :: n, nc
605 real(kind=rp), dimension(nc*n), intent(inout) :: u
606 type(c_ptr), intent(inout) :: strm
607 integer :: op
608 type(c_ptr) :: u_d
609
610 u_d = device_get_ptr(u)
611
612 call device_mpi_waitall(size(this%recv_pe), this%recv_buf%reqs)
613
614#ifdef HAVE_HIP
615 call hip_gs_unpack_vec(u_d, op, this%recv_buf%buf_v_d, &
616 this%recv_buf%dof_d, 0, this%recv_buf%total, nc, n, strm)
617#elif HAVE_CUDA
618 call cuda_gs_unpack_vec(u_d, op, this%recv_buf%buf_v_d, &
619 this%recv_buf%dof_d, 0, this%recv_buf%total, nc, n, strm)
620#else
621 call neko_error('gs_device_mpi: no backend')
622#endif
623
624 call device_mpi_waitall(size(this%send_pe), this%send_buf%reqs)
625
626 call device_sync(strm)
627
628 end subroutine gs_device_mpi_nbwait_vec
629
630end module gs_device_mpi
void cuda_gs_unpack(real *u_d, int op, real *buf_d, int *dof_d, int offset, int n, cudaStream_t stream)
Definition gs.cu:132
void cuda_gs_pack(void *u_d, void *buf_d, void *dof_d, int offset, int n, cudaStream_t stream)
Definition gs.cu:116
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)
Definition gs.cu:166
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)
Definition gs.cu:183
Return the device pointer for an associated Fortran array.
Definition device.F90:108
Copy data between host and device (or device and device)
Definition device.F90:72
Synchronize a device or stream.
Definition device.F90:114
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:61
integer, public pe_rank
MPI rank.
Definition comm.F90:58
Device abstraction, common interface for various accelerators.
Definition device.F90:34
subroutine, public device_event_record(event, stream)
Record a device event.
Definition device.F90:1571
integer, parameter, public host_to_device
Definition device.F90:48
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:240
subroutine, public device_event_destroy(event)
Destroy a device event.
Definition device.F90:1550
subroutine, public device_alloc(x_d, s)
Allocate memory on the device.
Definition device.F90:209
subroutine, public device_stream_create_with_priority(stream, flags, prio)
Create a device stream/command queue with priority.
Definition device.F90:1427
subroutine, public device_stream_wait_event(stream, event, flags)
Synchronize a device stream with an event.
Definition device.F90:1471
subroutine, public device_event_create(event, flags)
Create a device event queue.
Definition device.F90:1516
integer, public strm_high_prio
High priority stream setting.
Definition device.F90:66
subroutine, public device_memset(x_d, v, s, sync, strm)
Set memory on the device to a value.
Definition device.F90:263
subroutine, public device_stream_destroy(stream)
Destroy a device stream/command queue.
Definition device.F90:1449
Defines a gather-scatter communication method.
Definition gs_comm.f90:34
integer, parameter, public gs_vec_nc
Maximum number of components handled by the fused vector (multi-component) halo exchange used by gs_o...
Definition gs_comm.f90:49
Defines GPU aware MPI gather-scatter communication.
subroutine gs_device_mpi_nbsend_vec(this, u, n, nc, tag, deps, strm)
Fused nc-component send. u is the compact shared device buffer (component-outer, per-component stride...
subroutine gs_device_mpi_buf_init(this, pe_order, dof_stack, mark_dupes)
subroutine gs_device_mpi_nbwait(this, u, n, op, strm)
Wait for non-blocking operations.
subroutine gs_device_mpi_free(this)
Deallocate MPI based communication method.
subroutine gs_device_mpi_nbrecv_vec(this, tag, nc)
Post non-blocking receives for a fused nc-component exchange.
subroutine gs_device_mpi_nbwait_vec(this, u, n, nc, op, strm)
Wait for a fused nc-component exchange and unpack/reduce into u.
subroutine gs_device_mpi_buf_free(this)
subroutine gs_device_mpi_nbsend(this, u, n, tag, deps, strm)
Post non-blocking send operations.
subroutine gs_device_mpi_init(this, send_pe, recv_pe)
Initialise MPI based communication method.
subroutine gs_device_mpi_nbrecv(this, tag)
Post non-blocking receive operations.
Implements a hash table ADT.
Definition htable.f90:52
integer, parameter, public c_rp
Definition num_types.f90:13
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Implements a dynamic stack ADT.
Definition stack.f90:49
Utilities.
Definition utils.f90:35
Gather-scatter communication method.
Definition gs_comm.f90:52
Buffers for non-blocking communication and packing/unpacking.
Gather-scatter communication using device MPI. The arrays are indexed per PE like send_pe and @ recv_...
Integer based hash table.
Definition htable.f90:102
Integer based stack.
Definition stack.f90:77
#define max(a, b)
Definition tensor.cu:40