Neko 1.99.9
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) :: init_vec => gs_device_mpi_buf_init_vec
63 procedure, pass(this) :: free => gs_device_mpi_buf_free
64 end type gs_device_mpi_buf_t
65
68 type, public, extends(gs_comm_t) :: gs_device_mpi_t
69 type(gs_device_mpi_buf_t) :: send_buf
70 type(gs_device_mpi_buf_t) :: recv_buf
71 type(c_ptr), allocatable :: stream(:)
72 type(c_ptr), allocatable :: event(:)
73 integer :: nb_strtgy
74 type(c_ptr) :: send_event = c_null_ptr
75 contains
76 procedure, pass(this) :: init => gs_device_mpi_init
77 procedure, pass(this) :: free => gs_device_mpi_free
78 procedure, pass(this) :: nbsend => gs_device_mpi_nbsend
79 procedure, pass(this) :: nbrecv => gs_device_mpi_nbrecv
80 procedure, pass(this) :: nbwait => gs_device_mpi_nbwait
81 procedure, pass(this) :: init_vec => gs_device_mpi_init_vec
82 procedure, pass(this) :: nbsend_vec => gs_device_mpi_nbsend_vec
83 procedure, pass(this) :: nbrecv_vec => gs_device_mpi_nbrecv_vec
84 procedure, pass(this) :: nbwait_vec => gs_device_mpi_nbwait_vec
85 end type gs_device_mpi_t
86
87#ifdef HAVE_HIP
88 interface
89 subroutine hip_gs_pack(u_d, buf_d, dof_d, offset, n, stream) &
90 bind(c, name = 'hip_gs_pack')
91 use, intrinsic :: iso_c_binding
92 implicit none
93 integer(c_int), value :: n, offset
94 type(c_ptr), value :: u_d, buf_d, dof_d, stream
95 end subroutine hip_gs_pack
96 end interface
97
98 interface
99 subroutine hip_gs_unpack(u_d, op, buf_d, dof_d, offset, n, stream) &
100 bind(c, name = 'hip_gs_unpack')
101 use, intrinsic :: iso_c_binding
102 implicit none
103 integer(c_int), value :: op, offset, n
104 type(c_ptr), value :: u_d, buf_d, dof_d, stream
105 end subroutine hip_gs_unpack
106 end interface
107
108 interface
109 subroutine hip_gs_pack_vec(u_d, buf_d, dof_d, offset, n, nc, ns, stream) &
110 bind(c, name = 'hip_gs_pack_vec')
111 use, intrinsic :: iso_c_binding
112 implicit none
113 integer(c_int), value :: offset, n, nc, ns
114 type(c_ptr), value :: u_d, buf_d, dof_d, stream
115 end subroutine hip_gs_pack_vec
116 end interface
117
118 interface
119 subroutine hip_gs_unpack_vec(u_d, op, buf_d, dof_d, offset, n, nc, ns, &
120 stream) bind(c, name = 'hip_gs_unpack_vec')
121 use, intrinsic :: iso_c_binding
122 implicit none
123 integer(c_int), value :: op, offset, n, nc, ns
124 type(c_ptr), value :: u_d, buf_d, dof_d, stream
125 end subroutine hip_gs_unpack_vec
126 end interface
127#elif HAVE_CUDA
128 interface
129 subroutine cuda_gs_pack(u_d, buf_d, dof_d, offset, n, stream) &
130 bind(c, name = 'cuda_gs_pack')
131 use, intrinsic :: iso_c_binding
132 implicit none
133 integer(c_int), value :: n, offset
134 type(c_ptr), value :: u_d, buf_d, dof_d, stream
135 end subroutine cuda_gs_pack
136 end interface
137
138 interface
139 subroutine cuda_gs_unpack(u_d, op, buf_d, dof_d, offset, n, stream) &
140 bind(c, name = 'cuda_gs_unpack')
141 use, intrinsic :: iso_c_binding
142 implicit none
143 integer(c_int), value :: op, offset, n
144 type(c_ptr), value :: u_d, buf_d, dof_d, stream
145 end subroutine cuda_gs_unpack
146 end interface
147
148 interface
149 subroutine cuda_gs_pack_vec(u_d, buf_d, dof_d, offset, n, nc, ns, stream) &
150 bind(c, name = 'cuda_gs_pack_vec')
151 use, intrinsic :: iso_c_binding
152 implicit none
153 integer(c_int), value :: offset, n, nc, ns
154 type(c_ptr), value :: u_d, buf_d, dof_d, stream
155 end subroutine cuda_gs_pack_vec
156 end interface
157
158 interface
159 subroutine cuda_gs_unpack_vec(u_d, op, buf_d, dof_d, offset, n, nc, ns, &
160 stream) bind(c, name = 'cuda_gs_unpack_vec')
161 use, intrinsic :: iso_c_binding
162 implicit none
163 integer(c_int), value :: op, offset, n, nc, ns
164 type(c_ptr), value :: u_d, buf_d, dof_d, stream
165 end subroutine cuda_gs_unpack_vec
166 end interface
167#endif
168
169 interface
170 subroutine device_mpi_init_reqs(n, reqs) &
171 bind(c, name = 'device_mpi_init_reqs')
172 use, intrinsic :: iso_c_binding
173 implicit none
174 integer(c_int), value :: n
175 type(c_ptr) :: reqs
176 end subroutine device_mpi_init_reqs
177 end interface
178
179 interface
180 subroutine device_mpi_free_reqs(reqs) &
181 bind(c, name = 'device_mpi_free_reqs')
182 use, intrinsic :: iso_c_binding
183 implicit none
184 type(c_ptr) :: reqs
185 end subroutine device_mpi_free_reqs
186 end interface
187
188 interface
189 subroutine device_mpi_isend(buf_d, offset, nbytes, rank, tag, reqs, i) &
190 bind(c, name = 'device_mpi_isend')
191 use, intrinsic :: iso_c_binding
192 implicit none
193 integer(c_int), value :: offset, nbytes, rank, tag, i
194 type(c_ptr), value :: buf_d, reqs
195 end subroutine device_mpi_isend
196 end interface
197
198 interface
199 subroutine device_mpi_irecv(buf_d, offset, nbytes, rank, tag, reqs, i) &
200 bind(c, name = 'device_mpi_irecv')
201 use, intrinsic :: iso_c_binding
202 implicit none
203 integer(c_int), value :: offset, nbytes, rank, tag, i
204 type(c_ptr), value :: buf_d, reqs
205 end subroutine device_mpi_irecv
206 end interface
207
208 interface
209 integer(c_int) function device_mpi_test(reqs, i) &
210 bind(c, name = 'device_mpi_test')
211 use, intrinsic :: iso_c_binding
212 implicit none
213 integer(c_int), value :: i
214 type(c_ptr), value :: reqs
215 end function device_mpi_test
216 end interface
217
218 interface
219 subroutine device_mpi_waitall(n, reqs) &
220 bind(c, name = 'device_mpi_waitall')
221 use, intrinsic :: iso_c_binding
222 implicit none
223 integer(c_int), value :: n
224 type(c_ptr), value :: reqs
225 end subroutine device_mpi_waitall
226 end interface
227
228 interface
229 integer(c_int) function device_mpi_waitany(n, reqs, i) &
230 bind(c, name = 'device_mpi_waitany')
231 use, intrinsic :: iso_c_binding
232 implicit none
233 integer(c_int), value :: n
234 integer(c_int) :: i
235 type(c_ptr), value :: reqs
236 end function device_mpi_waitany
237 end interface
238
239contains
240
241 subroutine gs_device_mpi_buf_init(this, pe_order, dof_stack, mark_dupes)
242 class(gs_device_mpi_buf_t), intent(inout) :: this
243 integer, allocatable, intent(inout) :: pe_order(:)
244 type(stack_i4_t), allocatable, intent(inout) :: dof_stack(:)
245 logical, intent(in) :: mark_dupes
246 integer, allocatable :: dofs(:)
247 integer :: i, j, total
248 integer(c_size_t) :: sz
249 type(htable_i4_t) :: doftable
250 integer :: dupe, marked, k
251 real(c_rp) :: rp_dummy
252 integer(c_int32_t) :: i4_dummy
253
254 call device_mpi_init_reqs(size(pe_order), this%reqs)
255
256 allocate(this%ndofs(size(pe_order)))
257 allocate(this%offset(size(pe_order)))
258
259 total = 0
260 do i = 1, size(pe_order)
261 this%ndofs(i) = dof_stack(pe_order(i))%size()
262 this%offset(i) = total
263 total = total + this%ndofs(i)
264 end do
265
266 this%total = total
267
268 sz = c_sizeof(rp_dummy) * total
269 call device_alloc(this%buf_d, sz)
270 call device_memset(this%buf_d, 0, sz, sync = .true.)
271
272 sz = c_sizeof(i4_dummy) * total
273 call device_alloc(this%dof_d, sz)
274
275 if (mark_dupes) call doftable%init(2*total)
276 allocate(dofs(total))
277
278 ! Copy from dof_stack into dofs, optionally marking duplicates with doftable
279 marked = 0
280 do i = 1, size(pe_order)
281 ! %array() breaks on cray
282 select type (arr => dof_stack(pe_order(i))%data)
283 type is (integer)
284 do j = 1, this%ndofs(i)
285 k = this%offset(i) + j
286 if (mark_dupes) then
287 if (doftable%get(arr(j), dupe) .eq. 0) then
288 if (dofs(dupe) .gt. 0) then
289 dofs(dupe) = -dofs(dupe)
290 marked = marked + 1
291 end if
292 dofs(k) = -arr(j)
293 marked = marked + 1
294 else
295 call doftable%set(arr(j), k)
296 dofs(k) = arr(j)
297 end if
298 else
299 dofs(k) = arr(j)
300 end if
301 end do
302 end select
303 end do
304 call device_memcpy(dofs, this%dof_d, total, host_to_device, &
305 sync = .true.)
306 ! Syncing here prevents the memory in dofs to accidently be corrupted
307 ! while this memcpy is happening.
308 ! This might be happening in many other places as well. Karp 4/6-25
309
310 deallocate(dofs)
311 call doftable%free()
312
313 end subroutine gs_device_mpi_buf_init
314
318 class(gs_device_mpi_buf_t), intent(inout) :: this
319 integer(c_size_t) :: sz
320 real(c_rp) :: rp_dummy
321
322 sz = c_sizeof(rp_dummy) * gs_vec_nc * this%total
323 call device_alloc(this%buf_v_d, sz)
324 call device_memset(this%buf_v_d, 0, sz, sync = .true.)
325
326 end subroutine gs_device_mpi_buf_init_vec
327
328 subroutine gs_device_mpi_buf_free(this)
329 class(gs_device_mpi_buf_t), intent(inout) :: this
330
331 if (c_associated(this%reqs)) call device_mpi_free_reqs(this%reqs)
332
333 if (allocated(this%ndofs)) deallocate(this%ndofs)
334 if (allocated(this%offset)) deallocate(this%offset)
335
336 if (c_associated(this%buf_d)) call device_free(this%buf_d)
337 if (c_associated(this%buf_v_d)) call device_free(this%buf_v_d)
338 if (c_associated(this%dof_d)) call device_free(this%dof_d)
339 end subroutine gs_device_mpi_buf_free
340
342 subroutine gs_device_mpi_init(this, send_pe, recv_pe)
343 class(gs_device_mpi_t), intent(inout) :: this
344 type(stack_i4_t), intent(inout) :: send_pe
345 type(stack_i4_t), intent(inout) :: recv_pe
346 integer :: i, nstrm
347
348 call this%init_order(send_pe, recv_pe)
349
350 call this%send_buf%init(this%send_pe, this%send_dof, .false.)
351 call this%recv_buf%init(this%recv_pe, this%recv_dof, .true.)
352
353#if defined(HAVE_HIP) || defined(HAVE_CUDA)
354 ! Create a set of non-blocking streams. The per-peer streams and events
355 ! are indexed over both send_pe (pack) and recv_pe (unpack, sync), so
356 ! size them for the larger of the two peer lists.
357 nstrm = max(size(this%send_pe), size(this%recv_pe))
358 allocate(this%stream(nstrm))
359 do i = 1, nstrm
360 call device_stream_create_with_priority(this%stream(i), 1, &
362 end do
363
364 allocate(this%event(nstrm))
365 do i = 1, nstrm
366 call device_event_create(this%event(i), 2)
367 end do
368#endif
369
370
371 this%nb_strtgy = 0
372
373 this%vec_supported = .true.
374 this%vec_ready = .false.
375
376 end subroutine gs_device_mpi_init
377
382 subroutine gs_device_mpi_init_vec(this)
383 class(gs_device_mpi_t), intent(inout) :: this
384
385 call this%send_buf%init_vec()
386 call this%recv_buf%init_vec()
387
388 end subroutine gs_device_mpi_init_vec
389
391 subroutine gs_device_mpi_free(this)
392 class(gs_device_mpi_t), intent(inout) :: this
393 integer :: i
394
395 call this%send_buf%free()
396 call this%recv_buf%free()
397 this%vec_ready = .false.
398
399 call this%free_order()
400 call this%free_dofs()
401
402#if defined(HAVE_HIP) || defined(HAVE_CUDA)
403 if (allocated(this%stream)) then
404 do i = 1, size(this%stream)
405 call device_stream_destroy(this%stream(i))
406 end do
407 deallocate(this%stream)
408 end if
409
410 if (allocated(this%event)) then
411 do i = 1, size(this%event)
412 call device_event_destroy(this%event(i))
413 end do
414 deallocate(this%event)
415 end if
416#endif
417
418 end subroutine gs_device_mpi_free
419
421 subroutine gs_device_mpi_nbsend(this, u, n, tag, deps, strm)
422 class(gs_device_mpi_t), intent(inout) :: this
423 integer, intent(in) :: n
424 real(kind=rp), dimension(n), intent(inout) :: u
425 integer, intent(in) :: tag
426 type(c_ptr), intent(inout) :: deps
427 type(c_ptr), intent(inout) :: strm
428 integer :: i
429 type(c_ptr) :: u_d
430
431 u_d = device_get_ptr(u)
432
433 if (iand(this%nb_strtgy, 1) .eq. 0) then
434
435#ifdef HAVE_HIP
436 call hip_gs_pack(u_d, &
437 this%send_buf%buf_d, &
438 this%send_buf%dof_d, &
439 0, this%send_buf%total, &
440 strm)
441#elif HAVE_CUDA
442 call cuda_gs_pack(u_d, &
443 this%send_buf%buf_d, &
444 this%send_buf%dof_d, &
445 0, this%send_buf%total, &
446 strm)
447#else
448 call neko_error('gs_device_mpi: no backend')
449#endif
450
451 call device_sync(strm)
452
453 do i = 1, size(this%send_pe)
454 call device_mpi_isend(this%send_buf%buf_d, &
455 rp*this%send_buf%offset(i), &
456 rp*this%send_buf%ndofs(i), this%send_pe(i), tag, &
457 this%send_buf%reqs, i)
458 end do
459
460 else
461
462 do i = 1, size(this%send_pe)
463 call device_stream_wait_event(this%stream(i), deps, 0)
464#ifdef HAVE_HIP
465 call hip_gs_pack(u_d, &
466 this%send_buf%buf_d, &
467 this%send_buf%dof_d, &
468 this%send_buf%offset(i), &
469 this%send_buf%ndofs(i), &
470 this%stream(i))
471#elif HAVE_CUDA
472 call cuda_gs_pack(u_d, &
473 this%send_buf%buf_d, &
474 this%send_buf%dof_d, &
475 this%send_buf%offset(i), &
476 this%send_buf%ndofs(i), &
477 this%stream(i))
478#else
479 call neko_error('gs_device_mpi: no backend')
480#endif
481 end do
482
483 ! Consider adding a poll loop here once we have device_query in place
484 do i = 1, size(this%send_pe)
485 call device_sync(this%stream(i))
486 call device_mpi_isend(this%send_buf%buf_d, &
487 rp*this%send_buf%offset(i), &
488 rp*this%send_buf%ndofs(i), this%send_pe(i), tag, &
489 this%send_buf%reqs, i)
490 end do
491 end if
492
493 end subroutine gs_device_mpi_nbsend
494
496 subroutine gs_device_mpi_nbrecv(this, tag)
497 class(gs_device_mpi_t), intent(inout) :: this
498 integer, intent(in) :: tag
499 integer :: i
500
501 do i = 1, size(this%recv_pe)
502 call device_mpi_irecv(this%recv_buf%buf_d, rp*this%recv_buf%offset(i), &
503 rp*this%recv_buf%ndofs(i), this%recv_pe(i), tag, &
504 this%recv_buf%reqs, i)
505 end do
506
507 end subroutine gs_device_mpi_nbrecv
508
510 subroutine gs_device_mpi_nbwait(this, u, n, op, strm)
511 class(gs_device_mpi_t), intent(inout) :: this
512 integer, intent(in) :: n
513 real(kind=rp), dimension(n), intent(inout) :: u
514 type(c_ptr), intent(inout) :: strm
515 integer :: op, done_req, i
516 type(c_ptr) :: u_d
517
518 u_d = device_get_ptr(u)
519
520 if (iand(this%nb_strtgy, 2) .eq. 0) then
521 call device_mpi_waitall(size(this%recv_pe), this%recv_buf%reqs)
522
523#ifdef HAVE_HIP
524 call hip_gs_unpack(u_d, op, &
525 this%recv_buf%buf_d, &
526 this%recv_buf%dof_d, &
527 0, this%recv_buf%total, &
528 strm)
529#elif HAVE_CUDA
530 call cuda_gs_unpack(u_d, op, &
531 this%recv_buf%buf_d, &
532 this%recv_buf%dof_d, &
533 0, this%recv_buf%total, &
534 strm)
535#else
536 call neko_error('gs_device_mpi: no backend')
537#endif
538
539 call device_mpi_waitall(size(this%send_pe), this%send_buf%reqs)
540
541 ! Syncing here seems to prevent some race condition
542 call device_sync(strm)
543
544 else
545
546 do while (device_mpi_waitany(size(this%recv_pe), &
547 this%recv_buf%reqs, done_req) .ne. 0)
548
549#ifdef HAVE_HIP
550 call hip_gs_unpack(u_d, op, &
551 this%recv_buf%buf_d, &
552 this%recv_buf%dof_d, &
553 this%recv_buf%offset(done_req), &
554 this%recv_buf%ndofs(done_req), &
555 this%stream(done_req))
556#elif HAVE_CUDA
557 call cuda_gs_unpack(u_d, op, &
558 this%recv_buf%buf_d, &
559 this%recv_buf%dof_d, &
560 this%recv_buf%offset(done_req), &
561 this%recv_buf%ndofs(done_req), &
562 this%stream(done_req))
563#else
564 call neko_error('gs_device_mpi: no backend')
565#endif
566 call device_event_record(this%event(done_req), this%stream(done_req))
567 end do
568
569 call device_mpi_waitall(size(this%send_pe), this%send_buf%reqs)
570
571 ! Sync non-blocking streams
572 do done_req = 1, size(this%recv_pe)
573 call device_stream_wait_event(strm, &
574 this%event(done_req), 0)
575 end do
576
577 end if
578
579 end subroutine gs_device_mpi_nbwait
580
584 subroutine gs_device_mpi_nbsend_vec(this, u, n, nc, tag, deps, strm)
585 class(gs_device_mpi_t), intent(inout) :: this
586 integer, intent(in) :: n, nc
587 real(kind=rp), dimension(nc*n), intent(inout) :: u
588 integer, intent(in) :: tag
589 type(c_ptr), intent(inout) :: deps
590 type(c_ptr), intent(inout) :: strm
591 integer :: i
592 type(c_ptr) :: u_d
593
594 u_d = device_get_ptr(u)
595
596#ifdef HAVE_HIP
597 call hip_gs_pack_vec(u_d, this%send_buf%buf_v_d, this%send_buf%dof_d, &
598 0, this%send_buf%total, nc, n, strm)
599#elif HAVE_CUDA
600 call cuda_gs_pack_vec(u_d, this%send_buf%buf_v_d, this%send_buf%dof_d, &
601 0, this%send_buf%total, nc, n, strm)
602#else
603 call neko_error('gs_device_mpi: no backend')
604#endif
605
606 call device_sync(strm)
607
608 do i = 1, size(this%send_pe)
609 call device_mpi_isend(this%send_buf%buf_v_d, &
610 rp*nc*this%send_buf%offset(i), &
611 rp*nc*this%send_buf%ndofs(i), this%send_pe(i), tag, &
612 this%send_buf%reqs, i)
613 end do
614
615 end subroutine gs_device_mpi_nbsend_vec
616
618 subroutine gs_device_mpi_nbrecv_vec(this, tag, nc)
619 class(gs_device_mpi_t), intent(inout) :: this
620 integer, intent(in) :: tag, nc
621 integer :: i
622
623 do i = 1, size(this%recv_pe)
624 call device_mpi_irecv(this%recv_buf%buf_v_d, &
625 rp*nc*this%recv_buf%offset(i), &
626 rp*nc*this%recv_buf%ndofs(i), this%recv_pe(i), tag, &
627 this%recv_buf%reqs, i)
628 end do
629
630 end subroutine gs_device_mpi_nbrecv_vec
631
633 subroutine gs_device_mpi_nbwait_vec(this, u, n, nc, op, strm)
634 class(gs_device_mpi_t), intent(inout) :: this
635 integer, intent(in) :: n, nc
636 real(kind=rp), dimension(nc*n), intent(inout) :: u
637 type(c_ptr), intent(inout) :: strm
638 integer :: op
639 type(c_ptr) :: u_d
640
641 u_d = device_get_ptr(u)
642
643 call device_mpi_waitall(size(this%recv_pe), this%recv_buf%reqs)
644
645#ifdef HAVE_HIP
646 call hip_gs_unpack_vec(u_d, op, this%recv_buf%buf_v_d, &
647 this%recv_buf%dof_d, 0, this%recv_buf%total, nc, n, strm)
648#elif HAVE_CUDA
649 call cuda_gs_unpack_vec(u_d, op, this%recv_buf%buf_v_d, &
650 this%recv_buf%dof_d, 0, this%recv_buf%total, nc, n, strm)
651#else
652 call neko_error('gs_device_mpi: no backend')
653#endif
654
655 call device_mpi_waitall(size(this%send_pe), this%send_buf%reqs)
656
657 call device_sync(strm)
658
659 end subroutine gs_device_mpi_nbwait_vec
660
661end 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:113
Copy data between host and device (or device and device)
Definition device.F90:72
Synchronize a device or stream.
Definition device.F90:119
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:62
integer, public pe_rank
MPI rank.
Definition comm.F90:59
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:1644
integer, parameter, public host_to_device
Definition device.F90:48
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:243
subroutine, public device_event_destroy(event)
Destroy a device event.
Definition device.F90:1623
subroutine, public device_alloc(x_d, s)
Allocate memory on the device.
Definition device.F90:212
subroutine, public device_stream_create_with_priority(stream, flags, prio)
Create a device stream/command queue with priority.
Definition device.F90:1500
subroutine, public device_stream_wait_event(stream, event, flags)
Synchronize a device stream with an event.
Definition device.F90:1544
subroutine, public device_event_create(event, flags)
Create a device event queue.
Definition device.F90:1589
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:268
subroutine, public device_stream_destroy(stream)
Destroy a device stream/command queue.
Definition device.F90:1522
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:50
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_init_vec(this)
Allocate the fused vector send and receive slabs in device memory, sized for GS_VEC_NC components....
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_buf_init_vec(this)
Allocate this buffer's fused vector slab, sized for up to GS_VEC_NC components. Deferred to the first...
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:15
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Implements a dynamic stack ADT.
Definition stack.f90:49
Utilities.
Definition utils.f90:35
Gather-scatter communication method.
Definition gs_comm.f90:53
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