Neko 1.99.6
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
device.F90
Go to the documentation of this file.
1! Copyright (c) 2021-2026, 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!
34module device
35 use num_types, only : i8
36 use opencl_intf
37 use cuda_intf
38 use hip_intf
39 use metal_intf
41 use htable, only : htable_cptr_t, h_cptr_t
42 use utils, only : neko_error
44 use, intrinsic :: iso_c_binding
45 implicit none
46 private
47
48 integer, public, parameter :: host_to_device = 1, device_to_host = 2, &
50
52 type(c_ptr), public, bind(c) :: glb_cmd_queue = c_null_ptr
53
55 type(c_ptr), public, bind(c) :: aux_cmd_queue = c_null_ptr
56
57#ifdef HAVE_OPENCL
58
59 type(c_ptr), public, bind(c) :: prf_cmd_queue = c_null_ptr
60#endif
61
63 type(c_ptr), public, bind(c) :: glb_cmd_event
64
66 integer, public :: strm_high_prio
67
69 integer, public :: strm_low_prio
70
75 end interface device_memcpy
76
83 interface device_map
84 module procedure device_map_r1, device_map_r2, &
86 end interface device_map
87
92 end interface device_unmap
93
98 end interface device_associate
99
104 end interface device_associated
105
110 end interface device_deassociate
111
116 end interface device_get_ptr
117
119 interface device_sync
120 module procedure device_sync_device, device_sync_stream
121 end interface device_sync
122
125
134
135contains
136
137 subroutine device_init
138#if defined(HAVE_HIP) || defined(HAVE_CUDA) || \
139 defined(have_opencl) || defined(have_metal)
140 call device_addrtbl%init(64)
141
142#ifdef HAVE_HIP
144#elif HAVE_CUDA
146#elif HAVE_OPENCL
148#elif HAVE_METAL
149 call metal_init(glb_cmd_queue, aux_cmd_queue)
150#endif
152#endif
153
154 ! Check the device count against the number of MPI ranks
155 if (neko_bcknd_device .eq. 1) then
156 if (device_count() .ne. 1) then
157 call neko_error('Only one device is supported per MPI rank')
158 end if
159 end if
160 end subroutine device_init
161
163#if defined(HAVE_HIP) || defined(HAVE_CUDA) || \
164 defined(have_opencl) || defined(have_metal)
165 call device_addrtbl%free()
167
168#ifdef HAVE_HIP
170#elif HAVE_CUDA
172#elif HAVE_OPENCL
175#elif HAVE_METAL
176 call metal_finalize(glb_cmd_queue, aux_cmd_queue)
177#endif
178#endif
179 end subroutine device_finalize
180
181 subroutine device_name(name)
182 character(len=*), intent(inout) :: name
183
184#ifdef HAVE_HIP
185 call hip_device_name(name)
186#elif HAVE_CUDA
187 call cuda_device_name(name)
188#elif HAVE_OPENCL
189 call opencl_device_name(name)
190#elif HAVE_METAL
191 call metal_device_name(name)
192#endif
193 end subroutine device_name
194
196 integer function device_count()
197#ifdef HAVE_HIP
199#elif HAVE_CUDA
201#elif HAVE_OPENCL
203#elif HAVE_METAL
204 device_count = metal_device_count()
205#else
206 device_count = 0
207#endif
208 end function device_count
209
211 subroutine device_alloc(x_d, s)
212 type(c_ptr), intent(inout) :: x_d
213 integer(c_size_t) :: s
214 integer :: ierr
215
216 if (s .eq. 0) then
217 call device_sync()
218 x_d = c_null_ptr
219 return
220 end if
221#ifdef HAVE_HIP
222 if (hipmalloc(x_d, s) .ne. hipsuccess) then
223 call neko_error('Memory allocation on device failed')
224 end if
225#elif HAVE_CUDA
226 if (cudamalloc(x_d, s) .ne. cudasuccess) then
227 call neko_error('Memory allocation on device failed')
228 end if
229#elif HAVE_OPENCL
230 x_d = clcreatebuffer(glb_ctx, cl_mem_read_write, s, c_null_ptr, ierr)
231 if (ierr .ne. cl_success) then
232 call neko_error('Memory allocation on device failed')
233 end if
234#elif HAVE_METAL
235 if (metalalloc(x_d, s) .ne. metalsuccess) then
236 call neko_error('Memory allocation on device failed')
237 end if
238#endif
239 end subroutine device_alloc
240
242 subroutine device_free(x_d)
243 type(c_ptr), intent(inout) :: x_d
244#ifdef HAVE_HIP
245 ! Free via the mapping layer, which leaves zero-copy pointers
246 ! aliasing host memory untouched (unified memory architectures)
247 if (hipmapfree(x_d) .ne. hipsuccess) then
248 call neko_error('Memory deallocation on device failed')
249 end if
250#elif HAVE_CUDA
251 if (cudafree(x_d) .ne. cudasuccess) then
252 call neko_error('Memory deallocation on device failed')
253 end if
254#elif HAVE_OPENCL
255 if (clreleasememobject(x_d) .ne. cl_success) then
256 call neko_error('Memory deallocation on device failed')
257 end if
258#elif HAVE_METAL
259 if (metalfree(x_d) .ne. metalsuccess) then
260 call neko_error('Memory deallocation on device failed')
261 end if
262#endif
263 x_d = c_null_ptr
264 end subroutine device_free
265
267 subroutine device_memset(x_d, v, s, sync, strm)
268 type(c_ptr), intent(inout) :: x_d
269 integer(c_int), target, value :: v
270 integer(c_size_t), intent(in) :: s
271 logical, optional :: sync
272 type(c_ptr), optional :: strm
273 type(c_ptr) :: stream
274 logical :: sync_device
275
276 if (present(sync)) then
277 sync_device = sync
278 else
279 sync_device = .false.
280 end if
281
282 if (present(strm)) then
283 stream = strm
284 else
285 stream = glb_cmd_queue
286 end if
287
288#ifdef HAVE_HIP
289 ! Memset via the mapping layer, which handles zero-copy pointers
290 ! aliasing host memory (unified memory architectures)
291 if (hipmapmemset(x_d, v, s, stream) .ne. hipsuccess) then
292 call neko_error('Device memset async failed')
293 end if
294#elif HAVE_CUDA
295 if (cudamemsetasync(x_d, v, s, stream) .ne. cudasuccess) then
296 call neko_error('Device memset async failed')
297 end if
298#elif HAVE_OPENCL
299 if (clenqueuefillbuffer(stream, x_d, c_loc(v), c_sizeof(v), 0_i8, &
300 s, 0, c_null_ptr, c_null_ptr) .ne. cl_success) then
301 call neko_error('Device memset async failed')
302 end if
303#elif HAVE_METAL
304 if (metalmemset(x_d, v, s) .ne. metalsuccess) then
305 call neko_error('Device memset failed')
306 end if
307#endif
308
309 if (sync_device) then
310 call device_sync_stream(stream)
311 end if
312
313 end subroutine device_memset
314
316 subroutine device_memcpy_r1(x, x_d, n, dir, sync, strm)
317 integer, intent(in) :: n
318 class(*), intent(inout), target :: x(:)
319 type(c_ptr), intent(inout) :: x_d
320 integer, intent(in), value :: dir
321 logical :: sync
322 type(c_ptr), optional :: strm
323 type(c_ptr) :: ptr_h, copy_stream
324 integer(c_size_t) :: s
325
326 if (present(strm)) then
327 copy_stream = strm
328 else
329 copy_stream = glb_cmd_queue
330 end if
331
332 select type (x)
333 type is (integer)
334 s = n * int(4, c_size_t)
335 ptr_h = c_loc(x)
336 type is (integer(i8))
337 s = n * int(8, c_size_t)
338 ptr_h = c_loc(x)
339 type is (real)
340 s = n * int(4, c_size_t)
341 ptr_h = c_loc(x)
342 type is (double precision)
343 s = n * int(8, c_size_t)
344 ptr_h = c_loc(x)
345 class default
346 call neko_error('Unknown Fortran type')
347 end select
348
349 call device_memcpy_common(ptr_h, x_d, s, dir, sync, copy_stream)
350
351 end subroutine device_memcpy_r1
352
354 subroutine device_memcpy_r2(x, x_d, n, dir, sync, strm)
355 integer, intent(in) :: n
356 class(*), intent(inout), target :: x(:,:)
357 type(c_ptr), intent(inout) :: x_d
358 integer, intent(in), value :: dir
359 logical :: sync
360 type(c_ptr), optional :: strm
361 type(c_ptr) :: ptr_h, copy_stream
362 integer(c_size_t) :: s
363
364 if (present(strm)) then
365 copy_stream = strm
366 else
367 copy_stream = glb_cmd_queue
368 end if
369
370 select type (x)
371 type is (integer)
372 s = n * int(4, c_size_t)
373 ptr_h = c_loc(x)
374 type is (integer(i8))
375 s = n * int(8, c_size_t)
376 ptr_h = c_loc(x)
377 type is (real)
378 s = n * int(4, c_size_t)
379 ptr_h = c_loc(x)
380 type is (double precision)
381 s = n * int(8, c_size_t)
382 ptr_h = c_loc(x)
383 class default
384 call neko_error('Unknown Fortran type')
385 end select
386
387 call device_memcpy_common(ptr_h, x_d, s, dir, sync, copy_stream)
388
389 end subroutine device_memcpy_r2
390
392 subroutine device_memcpy_r3(x, x_d, n, dir, sync, strm)
393 integer, intent(in) :: n
394 class(*), intent(inout), target :: x(:,:,:)
395 type(c_ptr), intent(inout) :: x_d
396 integer, intent(in), value :: dir
397 logical :: sync
398 type(c_ptr), optional :: strm
399 type(c_ptr) :: ptr_h, copy_stream
400 integer(c_size_t) :: s
401
402 if (present(strm)) then
403 copy_stream = strm
404 else
405 copy_stream = glb_cmd_queue
406 end if
407
408 select type (x)
409 type is (integer)
410 s = n * int(4, c_size_t)
411 ptr_h = c_loc(x)
412 type is (integer(i8))
413 s = n * int(8, c_size_t)
414 ptr_h = c_loc(x)
415 type is (real)
416 s = n * int(4, c_size_t)
417 ptr_h = c_loc(x)
418 type is (double precision)
419 s = n * int(8, c_size_t)
420 ptr_h = c_loc(x)
421 class default
422 call neko_error('Unknown Fortran type')
423 end select
424
425 call device_memcpy_common(ptr_h, x_d, s, dir, sync, copy_stream)
426
427 end subroutine device_memcpy_r3
428
430 subroutine device_memcpy_r4(x, x_d, n, dir, sync, strm)
431 integer, intent(in) :: n
432 class(*), intent(inout), target :: x(:,:,:,:)
433 type(c_ptr), intent(inout) :: x_d
434 integer, intent(in), value :: dir
435 logical :: sync
436 type(c_ptr), optional :: strm
437 type(c_ptr) :: ptr_h, copy_stream
438 integer(c_size_t) :: s
439
440 if (present(strm)) then
441 copy_stream = strm
442 else
443 copy_stream = glb_cmd_queue
444 end if
445
446 select type (x)
447 type is (integer)
448 s = n * int(4, c_size_t)
449 ptr_h = c_loc(x)
450 type is (integer(i8))
451 s = n * int(8, c_size_t)
452 ptr_h = c_loc(x)
453 type is (real)
454 s = n * int(4, c_size_t)
455 ptr_h = c_loc(x)
456 type is (double precision)
457 s = n * int(8, c_size_t)
458 ptr_h = c_loc(x)
459 class default
460 call neko_error('Unknown Fortran type')
461 end select
462
463 call device_memcpy_common(ptr_h, x_d, s, dir, sync, copy_stream)
464
465 end subroutine device_memcpy_r4
466
470 subroutine device_memcpy_cptr(dst, src, s, dir, sync, strm)
471 type(c_ptr), intent(inout) :: dst
472 type(c_ptr), intent(inout) :: src
473 integer(c_size_t), intent(in) :: s
474 integer, intent(in), value :: dir
475 logical, optional :: sync
476 type(c_ptr), optional :: strm
477 type(c_ptr) :: copy_stream
478 logical :: sync_device
479
480 if (present(sync)) then
481 sync_device = sync
482 else
483 sync_device = .false.
484 end if
485
486 if (present(strm)) then
487 copy_stream = strm
488 else
489 copy_stream = glb_cmd_queue
490 end if
491
492 call device_memcpy_common(dst, src, s, dir, sync_device, copy_stream)
493
494 end subroutine device_memcpy_cptr
495
499 subroutine device_memcpy_common(ptr_h, x_d, s, dir, sync_device, stream)
500 type(c_ptr), intent(inout) :: ptr_h
501 type(c_ptr), intent(inout) :: x_d
502 integer(c_size_t), intent(in) :: s
503 integer, intent(in), value :: dir
504 logical, intent(in) :: sync_device
505 type(c_ptr), intent(inout) :: stream
506
507 if (s .eq. 0) then
508 if (sync_device) then
509 call device_sync_stream(stream)
510 end if
511 return
512 end if
513
514#ifdef HAVE_HIP
515 ! Copies where the device pointer aliases the host pointer
516 ! (zero-copy mappings on unified memory) are skipped; a
517 ! requested sync still synchronizes the stream below. Other
518 ! copies go via the mapping layer, which handles zero-copy
519 ! pointers aliasing pageable host memory
520 if (dir .eq. host_to_device) then
521 if (.not. c_associated(x_d, ptr_h)) then
522 if (hipmapmemcpy(x_d, ptr_h, s, &
523 hipmemcpyhosttodevice, stream) .ne. hipsuccess) then
524 call neko_error('Device memcpy async (host-to-device) failed')
525 end if
526 end if
527 else if (dir .eq. device_to_host) then
528 if (.not. c_associated(ptr_h, x_d)) then
529 if (hipmapmemcpy(ptr_h, x_d, s, &
530 hipmemcpydevicetohost, stream) .ne. hipsuccess) then
531 call neko_error('Device memcpy async (device-to-host) failed')
532 end if
533 end if
534 else if (dir .eq. device_to_device) then
535 if (.not. c_associated(ptr_h, x_d)) then
536 if (hipmapmemcpy(ptr_h, x_d, s, hipmemcpydevicetodevice, stream) &
537 .ne. hipsuccess) then
538 call neko_error('Device memcpy async (device-to-device) failed')
539 end if
540 end if
541 else
542 call neko_error('Device memcpy failed (invalid direction')
543 end if
544 if (sync_device) then
545 call device_sync_stream(stream)
546 end if
547#elif HAVE_CUDA
548 if (dir .eq. host_to_device) then
549 if (cudamemcpyasync(x_d, ptr_h, s, cudamemcpyhosttodevice, stream) &
550 .ne. cudasuccess) then
551 call neko_error('Device memcpy async (host-to-device) failed')
552 end if
553 else if (dir .eq. device_to_host) then
554 if (cudamemcpyasync(ptr_h, x_d, s, cudamemcpydevicetohost, stream) &
555 .ne. cudasuccess) then
556 call neko_error('Device memcpy async (device-to-host) failed')
557 end if
558 else if (dir .eq. device_to_device) then
559 if (cudamemcpyasync(ptr_h, x_d, s, cudamemcpydevicetodevice, stream) &
560 .ne. cudasuccess) then
561 call neko_error('Device memcpy async (device-to-device) failed')
562 end if
563 else
564 call neko_error('Device memcpy failed (invalid direction')
565 end if
566 if (sync_device) then
567 call device_sync_stream(stream)
568 end if
569#elif HAVE_OPENCL
570 if (sync_device) then
571 if (dir .eq. host_to_device) then
572 if (clenqueuewritebuffer(stream, x_d, cl_true, 0_i8, s, &
573 ptr_h, 0, c_null_ptr, c_null_ptr) &
574 .ne. cl_success) then
575 call neko_error('Device memcpy (host-to-device) failed')
576 end if
577 else if (dir .eq. device_to_host) then
578 if (clenqueuereadbuffer(stream, x_d, cl_true, 0_i8, s, ptr_h, &
579 0, c_null_ptr, c_null_ptr) &
580 .ne. cl_success) then
581 call neko_error('Device memcpy (device-to-host) failed')
582 end if
583 else if (dir .eq. device_to_device) then
584 if (clenqueuecopybuffer(stream, x_d, ptr_h, 0_i8, 0_i8, s, &
585 0, c_null_ptr, c_null_ptr) &
586 .ne. cl_success) then
587 call neko_error('Device memcpy (device-to-device) failed')
588 end if
589 else
590 call neko_error('Device memcpy failed (invalid direction')
591 end if
592 else
593 if (dir .eq. host_to_device) then
594 if (clenqueuewritebuffer(stream, x_d, cl_false, 0_i8, s, &
595 ptr_h, 0, c_null_ptr, c_null_ptr) &
596 .ne. cl_success) then
597 call neko_error('Device memcpy (host-to-device) failed')
598 end if
599 else if (dir .eq. device_to_host) then
600 if (clenqueuereadbuffer(stream, x_d, cl_false, 0_i8, s, ptr_h,&
601 0, c_null_ptr, c_null_ptr) &
602 .ne. cl_success) then
603 call neko_error('Device memcpy (device-to-host) failed')
604 end if
605 else if (dir .eq. device_to_device) then
606 if (clenqueuecopybuffer(stream, x_d, ptr_h, 0_i8, 0_i8, s, &
607 0, c_null_ptr, c_null_ptr) &
608 .ne. cl_success) then
609 call neko_error('Device memcpy (device-to-device) failed')
610 end if
611 else
612 call neko_error('Device memcpy failed (invalid direction')
613 end if
614 end if
615#elif HAVE_METAL
616 ! Copies are synchronous on unified memory, the @a sync_device
617 ! and @a stream arguments have no effect
618 if (dir .eq. host_to_device) then
619 if (metalmemcpyhtod(x_d, ptr_h, s) .ne. metalsuccess) then
620 call neko_error('Device memcpy (host-to-device) failed')
621 end if
622 else if (dir .eq. device_to_host) then
623 if (metalmemcpydtoh(ptr_h, x_d, s) .ne. metalsuccess) then
624 call neko_error('Device memcpy (device-to-host) failed')
625 end if
626 else if (dir .eq. device_to_device) then
627 if (metalmemcpydtod(ptr_h, x_d, s) .ne. metalsuccess) then
628 call neko_error('Device memcpy (device-to-device) failed')
629 end if
630 else
631 call neko_error('Device memcpy failed (invalid direction')
632 end if
633#endif
634 end subroutine device_memcpy_common
635
637 subroutine device_associate_r1(x, x_d, n)
638 class(*), intent(inout), target :: x(:)
639 type(c_ptr), intent(inout) :: x_d
640 integer, intent(in), optional :: n
641 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
642 integer :: n_
643
644 if (present(n)) then
645 n_ = n
646 else
647 n_ = size(x)
648 end if
649
650 if (n_ .eq. 0) return
651 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
652 ' to a null device pointer for a non-empty array')
653
654 select type (x)
655 type is (integer)
656 htbl_ptr_h%ptr = c_loc(x)
657 type is (integer(i8))
658 htbl_ptr_h%ptr = c_loc(x)
659 type is (real)
660 htbl_ptr_h%ptr = c_loc(x)
661 type is (double precision)
662 htbl_ptr_h%ptr = c_loc(x)
663 class default
664 call neko_error('Unknown Fortran type')
665 end select
666
667 htbl_ptr_d%ptr = x_d
668
669 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
670
671 end subroutine device_associate_r1
672
674 subroutine device_associate_r2(x, x_d, n)
675 class(*), intent(inout), target :: x(:,:)
676 type(c_ptr), intent(inout) :: x_d
677 integer, intent(in), optional :: n
678 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
679 integer :: n_
680
681 if (present(n)) then
682 n_ = n
683 else
684 n_ = size(x)
685 end if
686
687 if (n_ .eq. 0) return
688 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
689 ' to a null device pointer for a non-empty array')
690
691 select type (x)
692 type is (integer)
693 htbl_ptr_h%ptr = c_loc(x)
694 type is (integer(i8))
695 htbl_ptr_h%ptr = c_loc(x)
696 type is (real)
697 htbl_ptr_h%ptr = c_loc(x)
698 type is (double precision)
699 htbl_ptr_h%ptr = c_loc(x)
700 class default
701 call neko_error('Unknown Fortran type')
702 end select
703
704 htbl_ptr_d%ptr = x_d
705
706 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
707
708 end subroutine device_associate_r2
709
711 subroutine device_associate_r3(x, x_d, n)
712 class(*), intent(inout), target :: x(:,:,:)
713 type(c_ptr), intent(inout) :: x_d
714 integer, intent(in), optional :: n
715 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
716 integer :: n_
717
718 if (present(n)) then
719 n_ = n
720 else
721 n_ = size(x)
722 end if
723
724 if (n_ .eq. 0) return
725 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
726 ' to a null device pointer for a non-empty array')
727 select type (x)
728 type is (integer)
729 htbl_ptr_h%ptr = c_loc(x)
730 type is (integer(i8))
731 htbl_ptr_h%ptr = c_loc(x)
732 type is (real)
733 htbl_ptr_h%ptr = c_loc(x)
734 type is (double precision)
735 htbl_ptr_h%ptr = c_loc(x)
736 class default
737 call neko_error('Unknown Fortran type')
738 end select
739
740 htbl_ptr_d%ptr = x_d
741
742 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
743
744 end subroutine device_associate_r3
745
747 subroutine device_associate_r4(x, x_d, n)
748 class(*), intent(inout), target :: x(:,:,:,:)
749 type(c_ptr), intent(inout) :: x_d
750 integer, intent(in), optional :: n
751 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
752 integer :: n_
753
754 if (present(n)) then
755 n_ = n
756 else
757 n_ = size(x)
758 end if
759
760 if (n_ .eq. 0) return
761 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
762 ' to a null device pointer for a non-empty array')
763
764 select type (x)
765 type is (integer)
766 htbl_ptr_h%ptr = c_loc(x)
767 type is (integer(i8))
768 htbl_ptr_h%ptr = c_loc(x)
769 type is (real)
770 htbl_ptr_h%ptr = c_loc(x)
771 type is (double precision)
772 htbl_ptr_h%ptr = c_loc(x)
773 class default
774 call neko_error('Unknown Fortran type')
775 end select
776
777 htbl_ptr_d%ptr = x_d
778
779 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
780
781 end subroutine device_associate_r4
782
785 class(*), intent(inout), target :: x(:)
786 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
787
788 select type (x)
789 type is (integer)
790 htbl_ptr_h%ptr = c_loc(x)
791 type is (integer(i8))
792 htbl_ptr_h%ptr = c_loc(x)
793 type is (real)
794 htbl_ptr_h%ptr = c_loc(x)
795 type is (double precision)
796 htbl_ptr_h%ptr = c_loc(x)
797 class default
798 call neko_error('Unknown Fortran type')
799 end select
800
801 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
802 call device_addrtbl%remove(htbl_ptr_h)
803 end if
804
805 end subroutine device_deassociate_r1
806
809 class(*), intent(inout), target :: x(:,:)
810 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
811
812 select type (x)
813 type is (integer)
814 htbl_ptr_h%ptr = c_loc(x)
815 type is (integer(i8))
816 htbl_ptr_h%ptr = c_loc(x)
817 type is (real)
818 htbl_ptr_h%ptr = c_loc(x)
819 type is (double precision)
820 htbl_ptr_h%ptr = c_loc(x)
821 class default
822 call neko_error('Unknown Fortran type')
823 end select
824
825 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
826 call device_addrtbl%remove(htbl_ptr_h)
827 end if
828
829 end subroutine device_deassociate_r2
830
833 class(*), intent(inout), target :: x(:,:,:)
834 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
835
836 select type (x)
837 type is (integer)
838 htbl_ptr_h%ptr = c_loc(x)
839 type is (integer(i8))
840 htbl_ptr_h%ptr = c_loc(x)
841 type is (real)
842 htbl_ptr_h%ptr = c_loc(x)
843 type is (double precision)
844 htbl_ptr_h%ptr = c_loc(x)
845 class default
846 call neko_error('Unknown Fortran type')
847 end select
848
849 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
850 call device_addrtbl%remove(htbl_ptr_h)
851 end if
852
853 end subroutine device_deassociate_r3
854
857 class(*), intent(inout), target :: x(:,:,:,:)
858 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
859
860 select type (x)
861 type is (integer)
862 htbl_ptr_h%ptr = c_loc(x)
863 type is (integer(i8))
864 htbl_ptr_h%ptr = c_loc(x)
865 type is (real)
866 htbl_ptr_h%ptr = c_loc(x)
867 type is (double precision)
868 htbl_ptr_h%ptr = c_loc(x)
869 class default
870 call neko_error('Unknown Fortran type')
871 end select
872
873 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
874 call device_addrtbl%remove(htbl_ptr_h)
875 end if
876
877 end subroutine device_deassociate_r4
878
883 subroutine device_map_common(ptr_h, x_d, s)
884 type(c_ptr), intent(in) :: ptr_h
885 type(c_ptr), intent(inout) :: x_d
886 integer(c_size_t), intent(in) :: s
887
888#ifdef HAVE_METAL
889 if (s .eq. 0) then
890 call device_sync()
891 x_d = c_null_ptr
892 return
893 end if
894
895 if (metalmap(x_d, ptr_h, s) .ne. metalsuccess) then
896 call neko_error('Memory map on device failed')
897 end if
898#elif HAVE_HIP
899 if (s .eq. 0) then
900 call device_sync()
901 x_d = c_null_ptr
902 return
903 end if
904
905 if (hipmap(x_d, ptr_h, s) .ne. hipsuccess) then
906 call neko_error('Memory map on device failed')
907 end if
908#else
909 call device_alloc(x_d, s)
910#endif
911
912 end subroutine device_map_common
913
915 subroutine device_map_r1(x, x_d, n)
916 integer, intent(in) :: n
917 class(*), intent(inout), target :: x(:)
918 type(c_ptr), intent(inout) :: x_d
919 type(c_ptr) :: ptr_h
920 integer(c_size_t) :: s
921
922 if (c_associated(x_d)) then
923 call neko_error('Device pointer already associated')
924 end if
925
926 select type (x)
927 type is (integer)
928 s = n * int(4, c_size_t)
929 ptr_h = c_loc(x)
930 type is (integer(i8))
931 s = n * int(8, c_size_t)
932 ptr_h = c_loc(x)
933 type is (real)
934 s = n * int(4, c_size_t)
935 ptr_h = c_loc(x)
936 type is (double precision)
937 s = n * int(8, c_size_t)
938 ptr_h = c_loc(x)
939 class default
940 call neko_error('Unknown Fortran type')
941 end select
942
943 call device_map_common(ptr_h, x_d, s)
944 call device_associate(x, x_d, n)
945
946 end subroutine device_map_r1
947
949 subroutine device_map_r2(x, x_d, n)
950 integer, intent(in) :: n
951 class(*), intent(inout), target :: x(:,:)
952 type(c_ptr), intent(inout) :: x_d
953 type(c_ptr) :: ptr_h
954 integer(c_size_t) :: s
955
956 if (c_associated(x_d)) then
957 call neko_error('Device pointer already associated')
958 end if
959
960 select type (x)
961 type is (integer)
962 s = n * int(4, c_size_t)
963 ptr_h = c_loc(x)
964 type is (integer(i8))
965 s = n * int(8, c_size_t)
966 ptr_h = c_loc(x)
967 type is (real)
968 s = n * int(4, c_size_t)
969 ptr_h = c_loc(x)
970 type is (double precision)
971 s = n * int(8, c_size_t)
972 ptr_h = c_loc(x)
973 class default
974 call neko_error('Unknown Fortran type')
975 end select
976
977 call device_map_common(ptr_h, x_d, s)
978 call device_associate(x, x_d, n)
979
980 end subroutine device_map_r2
981
983 subroutine device_map_r3(x, x_d, n)
984 integer, intent(in) :: n
985 class(*), intent(inout), target :: x(:,:,:)
986 type(c_ptr), intent(inout) :: x_d
987 type(c_ptr) :: ptr_h
988 integer(c_size_t) :: s
989
990 if (c_associated(x_d)) then
991 call neko_error('Device pointer already associated')
992 end if
993
994 select type (x)
995 type is (integer)
996 s = n * int(4, c_size_t)
997 ptr_h = c_loc(x)
998 type is (integer(i8))
999 s = n * int(8, c_size_t)
1000 ptr_h = c_loc(x)
1001 type is (real)
1002 s = n * int(4, c_size_t)
1003 ptr_h = c_loc(x)
1004 type is (double precision)
1005 s = n * int(8, c_size_t)
1006 ptr_h = c_loc(x)
1007 class default
1008 call neko_error('Unknown Fortran type')
1009 end select
1010
1011 call device_map_common(ptr_h, x_d, s)
1012 call device_associate(x, x_d, n)
1013
1014 end subroutine device_map_r3
1015
1017 subroutine device_map_r4(x, x_d, n)
1018 integer, intent(in) :: n
1019 class(*), intent(inout), target :: x(:,:,:,:)
1020 type(c_ptr), intent(inout) :: x_d
1021 type(c_ptr) :: ptr_h
1022 integer(c_size_t) :: s
1023
1024 if (c_associated(x_d)) then
1025 call neko_error('Device pointer already associated')
1026 end if
1027
1028 select type (x)
1029 type is (integer)
1030 s = n * int(4, c_size_t)
1031 ptr_h = c_loc(x)
1032 type is (integer(i8))
1033 s = n * int(8, c_size_t)
1034 ptr_h = c_loc(x)
1035 type is (real)
1036 s = n * int(4, c_size_t)
1037 ptr_h = c_loc(x)
1038 type is (double precision)
1039 s = n * int(8, c_size_t)
1040 ptr_h = c_loc(x)
1041 class default
1042 call neko_error('Unknown Fortran type')
1043 end select
1044
1045 call device_map_common(ptr_h, x_d, s)
1046 call device_associate(x, x_d, n)
1047
1048 end subroutine device_map_r4
1049
1051 subroutine device_unmap_r1(x, x_d)
1052 class(*), intent(inout), target :: x(:)
1053 type(c_ptr), intent(inout) :: x_d
1054 type(c_ptr) :: dev
1055 logical :: mapped
1056
1057 ! Whether dev has a non-null address, meaning that x is mapped.
1058 mapped = device_associated(x)
1059
1060 ! Repeated calls to this routine do nothing
1061 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1062 return
1063 end if
1064
1065 ! Device pointer associated with x, should be same as x_d if mapped
1066 if (mapped) then
1067 dev = device_get_ptr(x)
1068 else
1069 dev = c_null_ptr
1070 end if
1071
1072 ! Error if:
1073 ! 1) x is not mapped to a device pointer, but x_d is not null.
1074 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1075 ! 3) x is mapped to a device pointer that is not x_d.
1076 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1077 (.not. c_associated(dev, x_d))) then
1078 call neko_error('Inconsistent host/device mapping state in ' // &
1079 'device_unmap')
1080 end if
1081
1082 call device_deassociate(x)
1083 call device_free(x_d)
1084
1085 end subroutine device_unmap_r1
1086
1088 subroutine device_unmap_r2(x, x_d)
1089 class(*), intent(inout), target :: x(:,:)
1090 type(c_ptr), intent(inout) :: x_d
1091 type(c_ptr) :: dev
1092 logical :: mapped
1093
1094 ! Whether dev has a non-null address, meaning that x is mapped.
1095 mapped = device_associated(x)
1096
1097 ! Repeated calls to this routine do nothing
1098 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1099 return
1100 end if
1101
1102 ! Device pointer associated with x, should be same as x_d if mapped
1103 if (mapped) then
1104 dev = device_get_ptr(x)
1105 else
1106 dev = c_null_ptr
1107 end if
1108
1109 ! Error if:
1110 ! 1) x is not mapped to a device pointer, but x_d is not null.
1111 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1112 ! 3) x is mapped to a device pointer that is not x_d.
1113 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1114 (.not. c_associated(dev, x_d))) then
1115 call neko_error('Inconsistent host/device mapping state in ' // &
1116 'device_unmap')
1117 end if
1118
1119 call device_deassociate(x)
1120 call device_free(x_d)
1121
1122 end subroutine device_unmap_r2
1123
1125 subroutine device_unmap_r3(x, x_d)
1126 class(*), intent(inout), target :: x(:,:,:)
1127 type(c_ptr), intent(inout) :: x_d
1128 type(c_ptr) :: dev
1129 logical :: mapped
1130
1131 ! Whether dev has a non-null address, meaning that x is mapped.
1132 mapped = device_associated(x)
1133
1134 ! Repeated calls to this routine do nothing
1135 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1136 return
1137 end if
1138
1139 ! Device pointer associated with x, should be same as x_d if mapped
1140 if (mapped) then
1141 dev = device_get_ptr(x)
1142 else
1143 dev = c_null_ptr
1144 end if
1145
1146 ! Error if:
1147 ! 1) x is not mapped to a device pointer, but x_d is not null.
1148 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1149 ! 3) x is mapped to a device pointer that is not x_d.
1150 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1151 (.not. c_associated(dev, x_d))) then
1152 call neko_error('Inconsistent host/device mapping state in ' // &
1153 'device_unmap')
1154 end if
1155
1156 call device_deassociate(x)
1157 call device_free(x_d)
1158
1159 end subroutine device_unmap_r3
1160
1162 subroutine device_unmap_r4(x, x_d)
1163 class(*), intent(inout), target :: x(:,:,:,:)
1164 type(c_ptr), intent(inout) :: x_d
1165 type(c_ptr) :: dev
1166 logical :: mapped
1167
1168 ! Whether dev has a non-null address, meaning that x is mapped.
1169 mapped = device_associated(x)
1170
1171 ! Repeated calls to this routine do nothing
1172 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1173 return
1174 end if
1175
1176 ! Device pointer associated with x, should be same as x_d if mapped
1177 if (mapped) then
1178 dev = device_get_ptr(x)
1179 else
1180 dev = c_null_ptr
1181 end if
1182
1183 ! Error if:
1184 ! 1) x is not mapped to a device pointer, but x_d is not null.
1185 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1186 ! 3) x is mapped to a device pointer that is not x_d.
1187 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1188 (.not. c_associated(dev, x_d))) then
1189 call neko_error('Inconsistent host/device mapping state in ' // &
1190 'device_unmap')
1191 end if
1192
1193 call device_deassociate(x)
1194 call device_free(x_d)
1195
1196 end subroutine device_unmap_r4
1197
1199 function device_associated_r1(x) result(assoc)
1200 class(*), intent(inout), target :: x(:)
1201 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1202 logical :: assoc
1203
1204 select type (x)
1205 type is (integer)
1206 htbl_ptr_h%ptr = c_loc(x)
1207 type is (integer(i8))
1208 htbl_ptr_h%ptr = c_loc(x)
1209 type is (real)
1210 htbl_ptr_h%ptr = c_loc(x)
1211 type is (double precision)
1212 htbl_ptr_h%ptr = c_loc(x)
1213 class default
1214 call neko_error('Unknown Fortran type')
1215 end select
1216
1217 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1218 assoc = .true.
1219 else
1220 assoc = .false.
1221 end if
1222
1223 end function device_associated_r1
1224
1226 function device_associated_r2(x) result(assoc)
1227 class(*), intent(inout), target :: x(:,:)
1228 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1229 logical :: assoc
1230
1231 select type (x)
1232 type is (integer)
1233 htbl_ptr_h%ptr = c_loc(x)
1234 type is (integer(i8))
1235 htbl_ptr_h%ptr = c_loc(x)
1236 type is (real)
1237 htbl_ptr_h%ptr = c_loc(x)
1238 type is (double precision)
1239 htbl_ptr_h%ptr = c_loc(x)
1240 class default
1241 call neko_error('Unknown Fortran type')
1242 end select
1243
1244 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1245 assoc = .true.
1246 else
1247 assoc = .false.
1248 end if
1249
1250 end function device_associated_r2
1251
1253 function device_associated_r3(x) result(assoc)
1254 class(*), intent(inout), target :: x(:,:,:)
1255 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1256 logical :: assoc
1257
1258 select type (x)
1259 type is (integer)
1260 htbl_ptr_h%ptr = c_loc(x)
1261 type is (integer(i8))
1262 htbl_ptr_h%ptr = c_loc(x)
1263 type is (real)
1264 htbl_ptr_h%ptr = c_loc(x)
1265 type is (double precision)
1266 htbl_ptr_h%ptr = c_loc(x)
1267 class default
1268 call neko_error('Unknown Fortran type')
1269 end select
1270
1271 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1272 assoc = .true.
1273 else
1274 assoc = .false.
1275 end if
1276
1277 end function device_associated_r3
1278
1280 function device_associated_r4(x) result(assoc)
1281 class(*), intent(inout), target :: x(:,:,:,:)
1282 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1283 logical :: assoc
1284
1285 select type (x)
1286 type is (integer)
1287 htbl_ptr_h%ptr = c_loc(x)
1288 type is (integer(i8))
1289 htbl_ptr_h%ptr = c_loc(x)
1290 type is (real)
1291 htbl_ptr_h%ptr = c_loc(x)
1292 type is (double precision)
1293 htbl_ptr_h%ptr = c_loc(x)
1294 class default
1295 call neko_error('Unknown Fortran type')
1296 end select
1297
1298 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1299 assoc = .true.
1300 else
1301 assoc = .false.
1302 end if
1303
1304 end function device_associated_r4
1305
1308 class(*), intent(in), target :: x(:)
1309 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1310 type(c_ptr) :: device_get_ptr_r1
1311
1312 device_get_ptr_r1 = c_null_ptr
1313
1314 select type (x)
1315 type is (integer)
1316 htbl_ptr_h%ptr = c_loc(x)
1317 type is (integer(i8))
1318 htbl_ptr_h%ptr = c_loc(x)
1319 type is (real)
1320 htbl_ptr_h%ptr = c_loc(x)
1321 type is (double precision)
1322 htbl_ptr_h%ptr = c_loc(x)
1323 class default
1324 call neko_error('Unknown Fortran type')
1325 end select
1326
1327 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1328 device_get_ptr_r1 = htbl_ptr_d%ptr
1329 else
1330 call neko_error('Array not associated with device')
1331 end if
1332 end function device_get_ptr_r1
1333
1336 class(*), intent(in), target :: x(:,:)
1337 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1338 type(c_ptr) :: device_get_ptr_r2
1339
1340 device_get_ptr_r2 = c_null_ptr
1341
1342 select type (x)
1343 type is (integer)
1344 htbl_ptr_h%ptr = c_loc(x)
1345 type is (integer(i8))
1346 htbl_ptr_h%ptr = c_loc(x)
1347 type is (real)
1348 htbl_ptr_h%ptr = c_loc(x)
1349 type is (double precision)
1350 htbl_ptr_h%ptr = c_loc(x)
1351 class default
1352 call neko_error('Unknown Fortran type')
1353 end select
1354
1355 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1356 device_get_ptr_r2 = htbl_ptr_d%ptr
1357 else
1358 call neko_error('Array not associated with device')
1359 end if
1360 end function device_get_ptr_r2
1361
1364 class(*), intent(in), target :: x(:,:,:)
1365 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1366 type(c_ptr) :: device_get_ptr_r3
1367
1368 device_get_ptr_r3 = c_null_ptr
1369
1370 select type (x)
1371 type is (integer)
1372 htbl_ptr_h%ptr = c_loc(x)
1373 type is (integer(i8))
1374 htbl_ptr_h%ptr = c_loc(x)
1375 type is (real)
1376 htbl_ptr_h%ptr = c_loc(x)
1377 type is (double precision)
1378 htbl_ptr_h%ptr = c_loc(x)
1379 class default
1380 call neko_error('Unknown Fortran type')
1381 end select
1382
1383 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1384 device_get_ptr_r3 = htbl_ptr_d%ptr
1385 else
1386 call neko_error('Array not associated with device')
1387 end if
1388 end function device_get_ptr_r3
1389
1392 class(*), intent(in), target :: x(:,:,:,:)
1393 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1394 type(c_ptr) :: device_get_ptr_r4
1395
1396 device_get_ptr_r4 = c_null_ptr
1397
1398 select type (x)
1399 type is (integer)
1400 htbl_ptr_h%ptr = c_loc(x)
1401 type is (integer(i8))
1402 htbl_ptr_h%ptr = c_loc(x)
1403 type is (real)
1404 htbl_ptr_h%ptr = c_loc(x)
1405 type is (double precision)
1406 htbl_ptr_h%ptr = c_loc(x)
1407 class default
1408 call neko_error('Unknown Fortran type')
1409 end select
1410
1411 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1412 device_get_ptr_r4 = htbl_ptr_d%ptr
1413 else
1414 call neko_error('Array not associated with device')
1415 end if
1416 end function device_get_ptr_r4
1417
1420#ifdef HAVE_HIP
1421 if (hipdevicesynchronize() .ne. hipsuccess) then
1422 call neko_error('Error during device sync')
1423 end if
1424#elif HAVE_CUDA
1425 if (cudadevicesynchronize() .ne. cudasuccess) then
1426 call neko_error('Error during device sync')
1427 end if
1428#elif HAVE_OPENCL
1429 if (clfinish(glb_cmd_queue) .ne. cl_success) then
1430 call neko_error('Error during device sync')
1431 end if
1432#elif HAVE_METAL
1433 if (metaldevicesynchronize() .ne. metalsuccess) then
1434 call neko_error('Error during device sync')
1435 end if
1436#endif
1437 end subroutine device_sync_device
1438
1440 subroutine device_sync_stream(stream)
1441 type(c_ptr), intent(in) :: stream
1442#ifdef HAVE_HIP
1443 if (hipstreamsynchronize(stream) .ne. hipsuccess) then
1444 call neko_error('Error during stream sync')
1445 end if
1446#elif HAVE_CUDA
1447 if (cudastreamsynchronize(stream) .ne. cudasuccess) then
1448 call neko_error('Error during stream sync')
1449 end if
1450#elif HAVE_OPENCL
1451 if (clfinish(stream) .ne. cl_success) then
1452 call neko_error('Error during stream sync')
1453 end if
1454#elif HAVE_METAL
1455 if (metalstreamsynchronize(stream) .ne. metalsuccess) then
1456 call neko_error('Error during stream sync')
1457 end if
1458#endif
1459 end subroutine device_sync_stream
1460
1462 subroutine device_stream_create(stream, flags)
1463 type(c_ptr), intent(inout) :: stream
1464 integer, optional :: flags
1465 integer :: ierr
1466#ifdef HAVE_HIP
1467 if (present(flags)) then
1468 if (hipstreamcreatewithflags(stream, flags) .ne. hipsuccess) then
1469 call neko_error('Error during stream create (w. flags)')
1470 end if
1471 else
1472 if (hipstreamcreate(stream) .ne. hipsuccess) then
1473 call neko_error('Error during stream create')
1474 end if
1475 end if
1476#elif HAVE_CUDA
1477 if (present(flags)) then
1478 if (cudastreamcreatewithflags(stream, flags) .ne. cudasuccess) then
1479 call neko_error('Error during stream create (w. flags)')
1480 end if
1481 else
1482 if (cudastreamcreate(stream) .ne. cudasuccess) then
1483 call neko_error('Error during stream create')
1484 end if
1485 end if
1486#elif HAVE_OPENCL
1487 stream = clcreatecommandqueue(glb_ctx, glb_device_id, 0_i8, ierr)
1488 if (ierr .ne. cl_success) then
1489 call neko_error('Error during stream create')
1490 end if
1491#elif HAVE_METAL
1492 if (metalstreamcreate(stream) .ne. metalsuccess) then
1493 call neko_error('Error during stream create')
1494 end if
1495#endif
1496 end subroutine device_stream_create
1497
1499 subroutine device_stream_create_with_priority(stream, flags, prio)
1500 type(c_ptr), intent(inout) :: stream
1501 integer, intent(in) :: flags, prio
1502#ifdef HAVE_HIP
1503 if (hipstreamcreatewithpriority(stream, flags, prio) .ne. hipsuccess) then
1504 call neko_error('Error during stream create (w. priority)')
1505 end if
1506#elif HAVE_CUDA
1507 if (cudastreamcreatewithpriority(stream, flags, prio) .ne. cudasuccess) then
1508 call neko_error('Error during stream create (w. priority)')
1509 end if
1510#elif HAVE_OPENCL
1511 call neko_error('Not implemented yet')
1512#elif HAVE_METAL
1513 ! Metal command queues have no priority, create a plain queue
1514 if (metalstreamcreate(stream) .ne. metalsuccess) then
1515 call neko_error('Error during stream create (w. priority)')
1516 end if
1517#endif
1519
1521 subroutine device_stream_destroy(stream)
1522 type(c_ptr), intent(inout) :: stream
1523#ifdef HAVE_HIP
1524 if (hipstreamdestroy(stream) .ne. hipsuccess) then
1525 call neko_error('Error during stream destroy')
1526 end if
1527#elif HAVE_CUDA
1528 if (cudastreamdestroy(stream) .ne. cudasuccess) then
1529 call neko_error('Error during stream destroy')
1530 end if
1531#elif HAVE_OPENCL
1532 if (clreleasecommandqueue(stream) .ne. cl_success) then
1533 call neko_error('Error during stream destroy')
1534 end if
1535#elif HAVE_METAL
1536 if (metalstreamdestroy(stream) .ne. metalsuccess) then
1537 call neko_error('Error during stream destroy')
1538 end if
1539#endif
1540 end subroutine device_stream_destroy
1541
1543 subroutine device_stream_wait_event(stream, event, flags)
1544 type(c_ptr), intent(in) :: stream
1545 type(c_ptr), target, intent(in) :: event
1546 integer :: flags
1547#ifdef HAVE_HIP
1548 if (hipstreamwaitevent(stream, event, flags) .ne. hipsuccess) then
1549 call neko_error('Error during stream sync')
1550 end if
1551#elif HAVE_CUDA
1552 if (cudastreamwaitevent(stream, event, flags) .ne. cudasuccess) then
1553 call neko_error('Error during stream sync')
1554 end if
1555#elif HAVE_OPENCL
1556 if (clenqueuebarrier(stream) .ne. cl_success) then
1557 call neko_error('Error during barrier')
1558 end if
1559 if (clenqueuewaitforevents(stream, 1, c_loc(event)) .ne. cl_success) then
1560 call neko_error('Error during stream sync')
1561 end if
1562#elif HAVE_METAL
1563 if (metalstreamwaitevent(stream, event) .ne. metalsuccess) then
1564 call neko_error('Error during stream sync')
1565 end if
1566#endif
1567 end subroutine device_stream_wait_event
1568
1571#if HAVE_CUDA
1572 if (cudaprofilerstart() .ne. cudasuccess) then
1573 call neko_error('Error starting profiler')
1574 end if
1575#endif
1576 end subroutine device_profiler_start
1577
1580#if HAVE_CUDA
1581 if (cudaprofilerstop() .ne. cudasuccess) then
1582 call neko_error('Error stopping profiler')
1583 end if
1584#endif
1585 end subroutine device_profiler_stop
1586
1588 subroutine device_event_create(event, flags)
1589 type(c_ptr), intent(inout) :: event
1590 integer, optional :: flags
1591 integer :: ierr
1592#ifdef HAVE_HIP
1593 if (present(flags)) then
1594 if (hipeventcreatewithflags(event, flags) .ne. hipsuccess) then
1595 call neko_error('Error during event create (w. flags)')
1596 end if
1597 else
1598 if (hipeventcreate(event) .ne. hipsuccess) then
1599 call neko_error('Error during event create')
1600 end if
1601 end if
1602#elif HAVE_CUDA
1603 if (present(flags)) then
1604 if (cudaeventcreatewithflags(event, flags) .ne. cudasuccess) then
1605 call neko_error('Error during event create (w. flags)')
1606 end if
1607 else
1608 if (cudaeventcreate(event) .ne. cudasuccess) then
1609 call neko_error('Error during event create')
1610 end if
1611 end if
1612#elif HAVE_OPENCL
1613 event = c_null_ptr
1614#elif HAVE_METAL
1615 if (metaleventcreate(event) .ne. metalsuccess) then
1616 call neko_error('Error during event create')
1617 end if
1618#endif
1619 end subroutine device_event_create
1620
1622 subroutine device_event_destroy(event)
1623 type(c_ptr), intent(inout) :: event
1624#ifdef HAVE_HIP
1625 if (hipeventdestroy(event) .ne. hipsuccess) then
1626 call neko_error('Error during event destroy')
1627 end if
1628#elif HAVE_CUDA
1629 if (cudaeventdestroy(event) .ne. cudasuccess) then
1630 call neko_error('Error during event destroy')
1631 end if
1632#elif HAVE_OPENCL
1633 event = c_null_ptr
1634#elif HAVE_METAL
1635 if (metaleventdestroy(event) .ne. metalsuccess) then
1636 call neko_error('Error during event destroy')
1637 end if
1638 event = c_null_ptr
1639#endif
1640 end subroutine device_event_destroy
1641
1643 subroutine device_event_record(event, stream)
1644 type(c_ptr), target, intent(in) :: event
1645 type(c_ptr), intent(in) :: stream
1646#ifdef HAVE_HIP
1647 if (hipeventrecord(event, stream) .ne. hipsuccess) then
1648 call neko_error('Error recording an event')
1649 end if
1650#elif HAVE_CUDA
1651 if (cudaeventrecord(event, stream) .ne. cudasuccess) then
1652 call neko_error('Error recording an event')
1653 end if
1654#elif HAVE_OPENCL
1655 if (clenqueuemarker(stream, c_loc(event)) .ne. cl_success) then
1656 call neko_error('Error recording an event')
1657 end if
1658#elif HAVE_METAL
1659 if (metaleventrecord(event, stream) .ne. metalsuccess) then
1660 call neko_error('Error recording an event')
1661 end if
1662#endif
1663 end subroutine device_event_record
1664
1666 subroutine device_event_sync(event)
1667 type(c_ptr), target, intent(in) :: event
1668#ifdef HAVE_HIP
1669 if (hipeventsynchronize(event) .ne. hipsuccess) then
1670 call neko_error('Error during event sync')
1671 end if
1672#elif HAVE_CUDA
1673 if (cudaeventsynchronize(event) .ne. cudasuccess) then
1674 call neko_error('Error during event sync')
1675 end if
1676#elif HAVE_OPENCL
1677 if (c_associated(event)) then
1678 if (clwaitforevents(1, c_loc(event)) .ne. cl_success) then
1679 call neko_error('Error during event sync')
1680 end if
1681 end if
1682#elif HAVE_METAL
1683 if (c_associated(event)) then
1684 if (metaleventsynchronize(event) .ne. metalsuccess) then
1685 call neko_error('Error during event sync')
1686 end if
1687 end if
1688#endif
1689 end subroutine device_event_sync
1690
1691end module device
double real
Associate a Fortran array to a (allocated) device pointer.
Definition device.F90:95
Check if a Fortran array is assoicated with a device pointer.
Definition device.F90:101
Deassociate a Fortran array from a device pointer.
Definition device.F90:107
Return the device pointer for an associated Fortran array.
Definition device.F90:113
Map a Fortran array to a device (allocate and associate)
Definition device.F90:83
Copy data between host and device (or device and device)
Definition device.F90:72
Synchronize a device or stream.
Definition device.F90:119
Unmap a Fortran array from a device (deassociate and free)
Definition device.F90:89
Map host memory to the device (zero-copy on unified memory architectures, e.g. MI300A,...
Definition hip_intf.F90:95
Free a device pointer obtained from hipMap (no-op for pointers aliasing host memory)
Definition hip_intf.F90:106
Copy between device/host pointers via the mapping layer (kernel-based copy under zero-copy,...
Definition hip_intf.F90:128
Memset on a device pointer obtained from hipMap (host-side memset for pointers aliasing host memory)
Definition hip_intf.F90:115
Fortran CUDA interface.
Definition cuda_intf.F90:34
subroutine cuda_device_name(name)
subroutine cuda_finalize(glb_cmd_queue, aux_cmd_queue)
@ cudamemcpydevicetohost
Definition cuda_intf.F90:54
@ cudamemcpydevicetodevice
Definition cuda_intf.F90:55
@ cudamemcpyhosttodevice
Definition cuda_intf.F90:53
integer function cuda_device_count()
Return the number of avaialble CUDA devices.
subroutine cuda_init(glb_cmd_queue, aux_cmd_queue, strm_high_prio, strm_low_prio)
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
subroutine device_associate_r4(x, x_d, n)
Associate a Fortran rank 4 array to a (allocated) device pointer.
Definition device.F90:748
subroutine, public device_event_sync(event)
Synchronize an event.
Definition device.F90:1667
subroutine device_associate_r1(x, x_d, n)
Associate a Fortran rank 1 array to a (allocated) device pointer.
Definition device.F90:638
subroutine, public device_finalize
Definition device.F90:163
integer, parameter, public device_to_device
Definition device.F90:48
type(c_ptr) function device_get_ptr_r4(x)
Return the device pointer for an associated Fortran rank 4 array.
Definition device.F90:1392
type(c_ptr) function device_get_ptr_r1(x)
Return the device pointer for an associated Fortran rank 1 array.
Definition device.F90:1308
integer, public strm_low_prio
Low priority stream setting.
Definition device.F90:69
integer, parameter, public host_to_device
Definition device.F90:48
subroutine device_map_r3(x, x_d, n)
Map a Fortran rank 3 array to a device (allocate and associate)
Definition device.F90:984
type(c_ptr), bind(C), public prf_cmd_queue
Profiling command queue.
Definition device.F90:59
type(htable_cptr_t) device_addrtbl
Table of host to device address mappings.
Definition device.F90:124
logical function device_associated_r3(x)
Check if a Fortran rank 3 array is assoicated with a device pointer.
Definition device.F90:1254
subroutine device_unmap_r4(x, x_d)
Unmap a Fortran rank 4 array from a device (deassociate and free)
Definition device.F90:1163
subroutine, public device_profiler_stop()
Stop device profiling.
Definition device.F90:1580
subroutine device_deassociate_r3(x)
Deassociate a Fortran rank 3 array from a device pointer.
Definition device.F90:833
subroutine, public device_sync_stream(stream)
Synchronize a device stream.
Definition device.F90:1441
type(c_ptr) function device_get_ptr_r3(x)
Return the device pointer for an associated Fortran rank 3 array.
Definition device.F90:1364
subroutine device_unmap_r2(x, x_d)
Unmap a Fortran rank 2 array from a device (deassociate and free)
Definition device.F90:1089
subroutine, public device_profiler_start()
Start device profiling.
Definition device.F90:1571
subroutine device_map_r2(x, x_d, n)
Map a Fortran rank 2 array to a device (allocate and associate)
Definition device.F90:950
subroutine device_memcpy_r2(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 2 arrays)
Definition device.F90:355
subroutine device_map_r4(x, x_d, n)
Map a Fortran rank 4 array to a device (allocate and associate)
Definition device.F90:1018
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:243
integer, parameter, public device_to_host
Definition device.F90:48
subroutine device_memcpy_cptr(dst, src, s, dir, sync, strm)
Copy data between host and device (or device and device) (c-pointers)
Definition device.F90:471
subroutine device_memcpy_common(ptr_h, x_d, s, dir, sync_device, stream)
Copy data between host and device.
Definition device.F90:500
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 device_associate_r2(x, x_d, n)
Associate a Fortran rank 2 array to a (allocated) device pointer.
Definition device.F90:675
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_create(stream, flags)
Create a device stream/command queue.
Definition device.F90:1463
subroutine device_deassociate_r4(x)
Deassociate a Fortran rank 4 array from a device pointer.
Definition device.F90:857
subroutine device_sync_device()
Synchronize the device.
Definition device.F90:1420
subroutine device_memcpy_r4(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 4 arrays)
Definition device.F90:431
subroutine, public device_stream_wait_event(stream, event, flags)
Synchronize a device stream with an event.
Definition device.F90:1544
subroutine device_map_r1(x, x_d, n)
Map a Fortran rank 1 array to a device (allocate and associate)
Definition device.F90:916
subroutine device_associate_r3(x, x_d, n)
Associate a Fortran rank 3 array to a (allocated) device pointer.
Definition device.F90:712
subroutine device_unmap_r1(x, x_d)
Unmap a Fortran rank 1 array from a device (deassociate and free)
Definition device.F90:1052
subroutine device_memcpy_r1(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 1 arrays)
Definition device.F90:317
type(c_ptr), bind(C), public glb_cmd_queue
Global command queue.
Definition device.F90:52
subroutine, public device_event_create(event, flags)
Create a device event queue.
Definition device.F90:1589
integer function, public device_count()
Return the number of available devices.
Definition device.F90:197
subroutine, public device_name(name)
Definition device.F90:182
logical function device_associated_r4(x)
Check if a Fortran rank 4 array is assoicated with a device pointer.
Definition device.F90:1281
logical function device_associated_r2(x)
Check if a Fortran rank 2 array is assoicated with a device pointer.
Definition device.F90:1227
integer, public strm_high_prio
High priority stream setting.
Definition device.F90:66
type(c_ptr), bind(C), public aux_cmd_queue
Aux command queue.
Definition device.F90:55
subroutine device_map_common(ptr_h, x_d, s)
Allocate device memory backing a mapped host array.
Definition device.F90:884
type(c_ptr) function device_get_ptr_r2(x)
Return the device pointer for an associated Fortran rank 2 array.
Definition device.F90:1336
subroutine device_unmap_r3(x, x_d)
Unmap a Fortran rank 3 array from a device (deassociate and free)
Definition device.F90:1126
subroutine device_deassociate_r1(x)
Deassociate a Fortran rank 1 array from a device pointer.
Definition device.F90:785
type(c_ptr), bind(C), public glb_cmd_event
Event for the global command queue.
Definition device.F90:63
subroutine device_deassociate_r2(x)
Deassociate a Fortran rank 2 array from a device pointer.
Definition device.F90:809
subroutine, public device_init
Definition device.F90:138
logical function device_associated_r1(x)
Check if a Fortran rank 1 array is assoicated with a device pointer.
Definition device.F90:1200
subroutine, public device_memset(x_d, v, s, sync, strm)
Set memory on the device to a value.
Definition device.F90:268
subroutine device_memcpy_r3(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 3 arrays)
Definition device.F90:393
subroutine, public device_stream_destroy(stream)
Destroy a device stream/command queue.
Definition device.F90:1522
Fortran HIP interface.
Definition hip_intf.F90:34
subroutine hip_device_name(name)
Definition hip_intf.F90:341
@ hipmemcpydevicetohost
Definition hip_intf.F90:72
@ hipmemcpydevicetodevice
Definition hip_intf.F90:73
@ hipmemcpyhosttodevice
Definition hip_intf.F90:71
subroutine hip_init(glb_cmd_queue, aux_cmd_queue, strm_high_prio, strm_low_prio)
Definition hip_intf.F90:290
subroutine hip_finalize(glb_cmd_queue, aux_cmd_queue)
Definition hip_intf.F90:312
integer function hip_device_count()
Return the number of available HIP devices.
Definition hip_intf.F90:358
Implements a hash table ADT.
Definition htable.f90:52
Fortran interface to the Metal device layer (see device/metal/metal.m)
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public i8
Definition num_types.f90:7
Fortran OpenCL interface.
subroutine opencl_device_name(name)
subroutine opencl_finalize(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
integer function opencl_device_count()
Return the number of OpenCL devices.
subroutine opencl_init(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
OpenCL JIT program library.
Definition prgm_lib.F90:2
subroutine, public opencl_prgm_lib_release
Definition prgm_lib.F90:134
Utilities.
Definition utils.f90:35
C pointer based hash table.
Definition htable.f90:162