Neko 1.99.9
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
135
136contains
137
138 subroutine device_init
139#if defined(HAVE_HIP) || defined(HAVE_CUDA) || \
140 defined(have_opencl) || defined(have_metal)
141 call device_addrtbl%init(64)
142
143#ifdef HAVE_HIP
145#elif HAVE_CUDA
147#elif HAVE_OPENCL
149#elif HAVE_METAL
150 call metal_init(glb_cmd_queue, aux_cmd_queue)
151#endif
153#endif
154
155 ! Check the device count against the number of MPI ranks
156 if (neko_bcknd_device .eq. 1) then
157 if (device_count() .ne. 1) then
158 call neko_error('Only one device is supported per MPI rank')
159 end if
160 end if
161 end subroutine device_init
162
164#if defined(HAVE_HIP) || defined(HAVE_CUDA) || \
165 defined(have_opencl) || defined(have_metal)
166 call device_addrtbl%free()
168
169#ifdef HAVE_HIP
171#elif HAVE_CUDA
173#elif HAVE_OPENCL
176#elif HAVE_METAL
177 call metal_finalize(glb_cmd_queue, aux_cmd_queue)
178#endif
179#endif
180 end subroutine device_finalize
181
182 subroutine device_name(name)
183 character(len=*), intent(inout) :: name
184
185#ifdef HAVE_HIP
186 call hip_device_name(name)
187#elif HAVE_CUDA
188 call cuda_device_name(name)
189#elif HAVE_OPENCL
190 call opencl_device_name(name)
191#elif HAVE_METAL
192 call metal_device_name(name)
193#endif
194 end subroutine device_name
195
197 integer function device_count()
198#ifdef HAVE_HIP
200#elif HAVE_CUDA
202#elif HAVE_OPENCL
204#elif HAVE_METAL
205 device_count = metal_device_count()
206#else
207 device_count = 0
208#endif
209 end function device_count
210
216 integer function device_mp_count()
217#ifdef HAVE_HIP
219#elif HAVE_CUDA
221#elif HAVE_OPENCL
223#elif HAVE_METAL
224 device_mp_count = metal_device_mp_count()
225#else
227#endif
228 end function device_mp_count
229
234 integer(kind=i8) function device_total_mem()
235#ifdef HAVE_HIP
237#elif HAVE_CUDA
239#elif HAVE_OPENCL
241#elif HAVE_METAL
242 device_total_mem = int(metal_device_total_mem(), i8)
243#else
244 device_total_mem = 0_i8
245#endif
246 end function device_total_mem
247
249 subroutine device_alloc(x_d, s)
250 type(c_ptr), intent(inout) :: x_d
251 integer(c_size_t) :: s
252 integer :: ierr
253
254 if (s .eq. 0) then
255 call device_sync()
256 x_d = c_null_ptr
257 return
258 end if
259#ifdef HAVE_HIP
260 if (hipmalloc(x_d, s) .ne. hipsuccess) then
261 call neko_error('Memory allocation on device failed')
262 end if
263#elif HAVE_CUDA
264 if (cudamalloc(x_d, s) .ne. cudasuccess) then
265 call neko_error('Memory allocation on device failed')
266 end if
267#elif HAVE_OPENCL
268 x_d = clcreatebuffer(glb_ctx, cl_mem_read_write, s, c_null_ptr, ierr)
269 if (ierr .ne. cl_success) then
270 call neko_error('Memory allocation on device failed')
271 end if
272#elif HAVE_METAL
273 if (metalalloc(x_d, s) .ne. metalsuccess) then
274 call neko_error('Memory allocation on device failed')
275 end if
276#endif
277 end subroutine device_alloc
278
280 subroutine device_free(x_d)
281 type(c_ptr), intent(inout) :: x_d
282#ifdef HAVE_HIP
283 ! Free via the mapping layer, which leaves zero-copy pointers
284 ! aliasing host memory untouched (unified memory architectures)
285 if (hipmapfree(x_d) .ne. hipsuccess) then
286 call neko_error('Memory deallocation on device failed')
287 end if
288#elif HAVE_CUDA
289 if (cudafree(x_d) .ne. cudasuccess) then
290 call neko_error('Memory deallocation on device failed')
291 end if
292#elif HAVE_OPENCL
293 if (clreleasememobject(x_d) .ne. cl_success) then
294 call neko_error('Memory deallocation on device failed')
295 end if
296#elif HAVE_METAL
297 if (metalfree(x_d) .ne. metalsuccess) then
298 call neko_error('Memory deallocation on device failed')
299 end if
300#endif
301 x_d = c_null_ptr
302 end subroutine device_free
303
305 subroutine device_memset(x_d, v, s, sync, strm)
306 type(c_ptr), intent(inout) :: x_d
307 integer(c_int), target, value :: v
308 integer(c_size_t), intent(in) :: s
309 logical, optional :: sync
310 type(c_ptr), optional :: strm
311 type(c_ptr) :: stream
312 logical :: sync_device
313
314 if (present(sync)) then
315 sync_device = sync
316 else
317 sync_device = .false.
318 end if
319
320 if (present(strm)) then
321 stream = strm
322 else
323 stream = glb_cmd_queue
324 end if
325
326#ifdef HAVE_HIP
327 ! Memset via the mapping layer, which handles zero-copy pointers
328 ! aliasing host memory (unified memory architectures)
329 if (hipmapmemset(x_d, v, s, stream) .ne. hipsuccess) then
330 call neko_error('Device memset async failed')
331 end if
332#elif HAVE_CUDA
333 if (cudamemsetasync(x_d, v, s, stream) .ne. cudasuccess) then
334 call neko_error('Device memset async failed')
335 end if
336#elif HAVE_OPENCL
337 if (clenqueuefillbuffer(stream, x_d, c_loc(v), c_sizeof(v), 0_i8, &
338 s, 0, c_null_ptr, c_null_ptr) .ne. cl_success) then
339 call neko_error('Device memset async failed')
340 end if
341#elif HAVE_METAL
342 if (metalmemset(x_d, v, s) .ne. metalsuccess) then
343 call neko_error('Device memset failed')
344 end if
345#endif
346
347 if (sync_device) then
348 call device_sync_stream(stream)
349 end if
350
351 end subroutine device_memset
352
354 subroutine device_memcpy_r1(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_r1
390
392 subroutine device_memcpy_r2(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_r2
428
430 subroutine device_memcpy_r3(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_r3
466
468 subroutine device_memcpy_r4(x, x_d, n, dir, sync, strm)
469 integer, intent(in) :: n
470 class(*), intent(inout), target :: x(:,:,:,:)
471 type(c_ptr), intent(inout) :: x_d
472 integer, intent(in), value :: dir
473 logical :: sync
474 type(c_ptr), optional :: strm
475 type(c_ptr) :: ptr_h, copy_stream
476 integer(c_size_t) :: s
477
478 if (present(strm)) then
479 copy_stream = strm
480 else
481 copy_stream = glb_cmd_queue
482 end if
483
484 select type (x)
485 type is (integer)
486 s = n * int(4, c_size_t)
487 ptr_h = c_loc(x)
488 type is (integer(i8))
489 s = n * int(8, c_size_t)
490 ptr_h = c_loc(x)
491 type is (real)
492 s = n * int(4, c_size_t)
493 ptr_h = c_loc(x)
494 type is (double precision)
495 s = n * int(8, c_size_t)
496 ptr_h = c_loc(x)
497 class default
498 call neko_error('Unknown Fortran type')
499 end select
500
501 call device_memcpy_common(ptr_h, x_d, s, dir, sync, copy_stream)
502
503 end subroutine device_memcpy_r4
504
508 subroutine device_memcpy_cptr(dst, src, s, dir, sync, strm)
509 type(c_ptr), intent(inout) :: dst
510 type(c_ptr), intent(inout) :: src
511 integer(c_size_t), intent(in) :: s
512 integer, intent(in), value :: dir
513 logical, optional :: sync
514 type(c_ptr), optional :: strm
515 type(c_ptr) :: copy_stream
516 logical :: sync_device
517
518 if (present(sync)) then
519 sync_device = sync
520 else
521 sync_device = .false.
522 end if
523
524 if (present(strm)) then
525 copy_stream = strm
526 else
527 copy_stream = glb_cmd_queue
528 end if
529
530 call device_memcpy_common(dst, src, s, dir, sync_device, copy_stream)
531
532 end subroutine device_memcpy_cptr
533
537 subroutine device_memcpy_common(ptr_h, x_d, s, dir, sync_device, stream)
538 type(c_ptr), intent(inout) :: ptr_h
539 type(c_ptr), intent(inout) :: x_d
540 integer(c_size_t), intent(in) :: s
541 integer, intent(in), value :: dir
542 logical, intent(in) :: sync_device
543 type(c_ptr), intent(inout) :: stream
544
545 if (s .eq. 0) then
546 if (sync_device) then
547 call device_sync_stream(stream)
548 end if
549 return
550 end if
551
552#ifdef HAVE_HIP
553 ! Copies where the device pointer aliases the host pointer
554 ! (zero-copy mappings on unified memory) are skipped; a
555 ! requested sync still synchronizes the stream below. Other
556 ! copies go via the mapping layer, which handles zero-copy
557 ! pointers aliasing pageable host memory
558 if (dir .eq. host_to_device) then
559 if (.not. c_associated(x_d, ptr_h)) then
560 if (hipmapmemcpy(x_d, ptr_h, s, &
561 hipmemcpyhosttodevice, stream) .ne. hipsuccess) then
562 call neko_error('Device memcpy async (host-to-device) failed')
563 end if
564 end if
565 else if (dir .eq. device_to_host) then
566 if (.not. c_associated(ptr_h, x_d)) then
567 if (hipmapmemcpy(ptr_h, x_d, s, &
568 hipmemcpydevicetohost, stream) .ne. hipsuccess) then
569 call neko_error('Device memcpy async (device-to-host) failed')
570 end if
571 end if
572 else if (dir .eq. device_to_device) then
573 if (.not. c_associated(ptr_h, x_d)) then
574 if (hipmapmemcpy(ptr_h, x_d, s, hipmemcpydevicetodevice, stream) &
575 .ne. hipsuccess) then
576 call neko_error('Device memcpy async (device-to-device) failed')
577 end if
578 end if
579 else
580 call neko_error('Device memcpy failed (invalid direction')
581 end if
582 if (sync_device) then
583 call device_sync_stream(stream)
584 end if
585#elif HAVE_CUDA
586 if (dir .eq. host_to_device) then
587 if (cudamemcpyasync(x_d, ptr_h, s, cudamemcpyhosttodevice, stream) &
588 .ne. cudasuccess) then
589 call neko_error('Device memcpy async (host-to-device) failed')
590 end if
591 else if (dir .eq. device_to_host) then
592 if (cudamemcpyasync(ptr_h, x_d, s, cudamemcpydevicetohost, stream) &
593 .ne. cudasuccess) then
594 call neko_error('Device memcpy async (device-to-host) failed')
595 end if
596 else if (dir .eq. device_to_device) then
597 if (cudamemcpyasync(ptr_h, x_d, s, cudamemcpydevicetodevice, stream) &
598 .ne. cudasuccess) then
599 call neko_error('Device memcpy async (device-to-device) failed')
600 end if
601 else
602 call neko_error('Device memcpy failed (invalid direction')
603 end if
604 if (sync_device) then
605 call device_sync_stream(stream)
606 end if
607#elif HAVE_OPENCL
608 if (sync_device) then
609 if (dir .eq. host_to_device) then
610 if (clenqueuewritebuffer(stream, x_d, cl_true, 0_i8, s, &
611 ptr_h, 0, c_null_ptr, c_null_ptr) &
612 .ne. cl_success) then
613 call neko_error('Device memcpy (host-to-device) failed')
614 end if
615 else if (dir .eq. device_to_host) then
616 if (clenqueuereadbuffer(stream, x_d, cl_true, 0_i8, s, ptr_h, &
617 0, c_null_ptr, c_null_ptr) &
618 .ne. cl_success) then
619 call neko_error('Device memcpy (device-to-host) failed')
620 end if
621 else if (dir .eq. device_to_device) then
622 if (clenqueuecopybuffer(stream, x_d, ptr_h, 0_i8, 0_i8, s, &
623 0, c_null_ptr, c_null_ptr) &
624 .ne. cl_success) then
625 call neko_error('Device memcpy (device-to-device) failed')
626 end if
627 else
628 call neko_error('Device memcpy failed (invalid direction')
629 end if
630 else
631 if (dir .eq. host_to_device) then
632 if (clenqueuewritebuffer(stream, x_d, cl_false, 0_i8, s, &
633 ptr_h, 0, c_null_ptr, c_null_ptr) &
634 .ne. cl_success) then
635 call neko_error('Device memcpy (host-to-device) failed')
636 end if
637 else if (dir .eq. device_to_host) then
638 if (clenqueuereadbuffer(stream, x_d, cl_false, 0_i8, s, ptr_h,&
639 0, c_null_ptr, c_null_ptr) &
640 .ne. cl_success) then
641 call neko_error('Device memcpy (device-to-host) failed')
642 end if
643 else if (dir .eq. device_to_device) then
644 if (clenqueuecopybuffer(stream, x_d, ptr_h, 0_i8, 0_i8, s, &
645 0, c_null_ptr, c_null_ptr) &
646 .ne. cl_success) then
647 call neko_error('Device memcpy (device-to-device) failed')
648 end if
649 else
650 call neko_error('Device memcpy failed (invalid direction')
651 end if
652 end if
653#elif HAVE_METAL
654 ! Copies are synchronous on unified memory, the @a sync_device
655 ! and @a stream arguments have no effect
656 if (dir .eq. host_to_device) then
657 if (metalmemcpyhtod(x_d, ptr_h, s) .ne. metalsuccess) then
658 call neko_error('Device memcpy (host-to-device) failed')
659 end if
660 else if (dir .eq. device_to_host) then
661 if (metalmemcpydtoh(ptr_h, x_d, s) .ne. metalsuccess) then
662 call neko_error('Device memcpy (device-to-host) failed')
663 end if
664 else if (dir .eq. device_to_device) then
665 if (metalmemcpydtod(ptr_h, x_d, s) .ne. metalsuccess) then
666 call neko_error('Device memcpy (device-to-device) failed')
667 end if
668 else
669 call neko_error('Device memcpy failed (invalid direction')
670 end if
671#endif
672 end subroutine device_memcpy_common
673
675 subroutine device_associate_r1(x, x_d, n)
676 class(*), intent(inout), target :: x(:)
677 type(c_ptr), intent(inout) :: x_d
678 integer, intent(in), optional :: n
679 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
680 integer :: n_
681
682 if (present(n)) then
683 n_ = n
684 else
685 n_ = size(x)
686 end if
687
688 if (n_ .eq. 0) return
689 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
690 ' to a null device pointer for a non-empty array')
691
692 select type (x)
693 type is (integer)
694 htbl_ptr_h%ptr = c_loc(x)
695 type is (integer(i8))
696 htbl_ptr_h%ptr = c_loc(x)
697 type is (real)
698 htbl_ptr_h%ptr = c_loc(x)
699 type is (double precision)
700 htbl_ptr_h%ptr = c_loc(x)
701 class default
702 call neko_error('Unknown Fortran type')
703 end select
704
705 htbl_ptr_d%ptr = x_d
706
707 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
708
709 end subroutine device_associate_r1
710
712 subroutine device_associate_r2(x, x_d, n)
713 class(*), intent(inout), target :: x(:,:)
714 type(c_ptr), intent(inout) :: x_d
715 integer, intent(in), optional :: n
716 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
717 integer :: n_
718
719 if (present(n)) then
720 n_ = n
721 else
722 n_ = size(x)
723 end if
724
725 if (n_ .eq. 0) return
726 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
727 ' to a null device pointer for a non-empty array')
728
729 select type (x)
730 type is (integer)
731 htbl_ptr_h%ptr = c_loc(x)
732 type is (integer(i8))
733 htbl_ptr_h%ptr = c_loc(x)
734 type is (real)
735 htbl_ptr_h%ptr = c_loc(x)
736 type is (double precision)
737 htbl_ptr_h%ptr = c_loc(x)
738 class default
739 call neko_error('Unknown Fortran type')
740 end select
741
742 htbl_ptr_d%ptr = x_d
743
744 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
745
746 end subroutine device_associate_r2
747
749 subroutine device_associate_r3(x, x_d, n)
750 class(*), intent(inout), target :: x(:,:,:)
751 type(c_ptr), intent(inout) :: x_d
752 integer, intent(in), optional :: n
753 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
754 integer :: n_
755
756 if (present(n)) then
757 n_ = n
758 else
759 n_ = size(x)
760 end if
761
762 if (n_ .eq. 0) return
763 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
764 ' to a null device pointer for a non-empty array')
765 select type (x)
766 type is (integer)
767 htbl_ptr_h%ptr = c_loc(x)
768 type is (integer(i8))
769 htbl_ptr_h%ptr = c_loc(x)
770 type is (real)
771 htbl_ptr_h%ptr = c_loc(x)
772 type is (double precision)
773 htbl_ptr_h%ptr = c_loc(x)
774 class default
775 call neko_error('Unknown Fortran type')
776 end select
777
778 htbl_ptr_d%ptr = x_d
779
780 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
781
782 end subroutine device_associate_r3
783
785 subroutine device_associate_r4(x, x_d, n)
786 class(*), intent(inout), target :: x(:,:,:,:)
787 type(c_ptr), intent(inout) :: x_d
788 integer, intent(in), optional :: n
789 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
790 integer :: n_
791
792 if (present(n)) then
793 n_ = n
794 else
795 n_ = size(x)
796 end if
797
798 if (n_ .eq. 0) return
799 if (.not. c_associated(x_d)) call neko_error('Attempting to associate' // &
800 ' to a null device pointer for a non-empty array')
801
802 select type (x)
803 type is (integer)
804 htbl_ptr_h%ptr = c_loc(x)
805 type is (integer(i8))
806 htbl_ptr_h%ptr = c_loc(x)
807 type is (real)
808 htbl_ptr_h%ptr = c_loc(x)
809 type is (double precision)
810 htbl_ptr_h%ptr = c_loc(x)
811 class default
812 call neko_error('Unknown Fortran type')
813 end select
814
815 htbl_ptr_d%ptr = x_d
816
817 call device_addrtbl%set(htbl_ptr_h, htbl_ptr_d)
818
819 end subroutine device_associate_r4
820
823 class(*), intent(inout), target :: x(:)
824 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
825
826 select type (x)
827 type is (integer)
828 htbl_ptr_h%ptr = c_loc(x)
829 type is (integer(i8))
830 htbl_ptr_h%ptr = c_loc(x)
831 type is (real)
832 htbl_ptr_h%ptr = c_loc(x)
833 type is (double precision)
834 htbl_ptr_h%ptr = c_loc(x)
835 class default
836 call neko_error('Unknown Fortran type')
837 end select
838
839 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
840 call device_addrtbl%remove(htbl_ptr_h)
841 end if
842
843 end subroutine device_deassociate_r1
844
847 class(*), intent(inout), target :: x(:,:)
848 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
849
850 select type (x)
851 type is (integer)
852 htbl_ptr_h%ptr = c_loc(x)
853 type is (integer(i8))
854 htbl_ptr_h%ptr = c_loc(x)
855 type is (real)
856 htbl_ptr_h%ptr = c_loc(x)
857 type is (double precision)
858 htbl_ptr_h%ptr = c_loc(x)
859 class default
860 call neko_error('Unknown Fortran type')
861 end select
862
863 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
864 call device_addrtbl%remove(htbl_ptr_h)
865 end if
866
867 end subroutine device_deassociate_r2
868
871 class(*), intent(inout), target :: x(:,:,:)
872 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
873
874 select type (x)
875 type is (integer)
876 htbl_ptr_h%ptr = c_loc(x)
877 type is (integer(i8))
878 htbl_ptr_h%ptr = c_loc(x)
879 type is (real)
880 htbl_ptr_h%ptr = c_loc(x)
881 type is (double precision)
882 htbl_ptr_h%ptr = c_loc(x)
883 class default
884 call neko_error('Unknown Fortran type')
885 end select
886
887 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
888 call device_addrtbl%remove(htbl_ptr_h)
889 end if
890
891 end subroutine device_deassociate_r3
892
895 class(*), intent(inout), target :: x(:,:,:,:)
896 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
897
898 select type (x)
899 type is (integer)
900 htbl_ptr_h%ptr = c_loc(x)
901 type is (integer(i8))
902 htbl_ptr_h%ptr = c_loc(x)
903 type is (real)
904 htbl_ptr_h%ptr = c_loc(x)
905 type is (double precision)
906 htbl_ptr_h%ptr = c_loc(x)
907 class default
908 call neko_error('Unknown Fortran type')
909 end select
910
911 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
912 call device_addrtbl%remove(htbl_ptr_h)
913 end if
914
915 end subroutine device_deassociate_r4
916
921 subroutine device_map_common(ptr_h, x_d, s)
922 type(c_ptr), intent(in) :: ptr_h
923 type(c_ptr), intent(inout) :: x_d
924 integer(c_size_t), intent(in) :: s
925
926#ifdef HAVE_METAL
927 if (s .eq. 0) then
928 call device_sync()
929 x_d = c_null_ptr
930 return
931 end if
932
933 if (metalmap(x_d, ptr_h, s) .ne. metalsuccess) then
934 call neko_error('Memory map on device failed')
935 end if
936#elif HAVE_HIP
937 if (s .eq. 0) then
938 call device_sync()
939 x_d = c_null_ptr
940 return
941 end if
942
943 if (hipmap(x_d, ptr_h, s) .ne. hipsuccess) then
944 call neko_error('Memory map on device failed')
945 end if
946#else
947 call device_alloc(x_d, s)
948#endif
949
950 end subroutine device_map_common
951
953 subroutine device_map_r1(x, x_d, n)
954 integer, intent(in) :: n
955 class(*), intent(inout), target :: x(:)
956 type(c_ptr), intent(inout) :: x_d
957 type(c_ptr) :: ptr_h
958 integer(c_size_t) :: s
959
960 if (c_associated(x_d)) then
961 call neko_error('Device pointer already associated')
962 end if
963
964 select type (x)
965 type is (integer)
966 s = n * int(4, c_size_t)
967 ptr_h = c_loc(x)
968 type is (integer(i8))
969 s = n * int(8, c_size_t)
970 ptr_h = c_loc(x)
971 type is (real)
972 s = n * int(4, c_size_t)
973 ptr_h = c_loc(x)
974 type is (double precision)
975 s = n * int(8, c_size_t)
976 ptr_h = c_loc(x)
977 class default
978 call neko_error('Unknown Fortran type')
979 end select
980
981 call device_map_common(ptr_h, x_d, s)
982 call device_associate(x, x_d, n)
983
984 end subroutine device_map_r1
985
987 subroutine device_map_r2(x, x_d, n)
988 integer, intent(in) :: n
989 class(*), intent(inout), target :: x(:,:)
990 type(c_ptr), intent(inout) :: x_d
991 type(c_ptr) :: ptr_h
992 integer(c_size_t) :: s
993
994 if (c_associated(x_d)) then
995 call neko_error('Device pointer already associated')
996 end if
997
998 select type (x)
999 type is (integer)
1000 s = n * int(4, c_size_t)
1001 ptr_h = c_loc(x)
1002 type is (integer(i8))
1003 s = n * int(8, c_size_t)
1004 ptr_h = c_loc(x)
1005 type is (real)
1006 s = n * int(4, c_size_t)
1007 ptr_h = c_loc(x)
1008 type is (double precision)
1009 s = n * int(8, c_size_t)
1010 ptr_h = c_loc(x)
1011 class default
1012 call neko_error('Unknown Fortran type')
1013 end select
1014
1015 call device_map_common(ptr_h, x_d, s)
1016 call device_associate(x, x_d, n)
1017
1018 end subroutine device_map_r2
1019
1021 subroutine device_map_r3(x, x_d, n)
1022 integer, intent(in) :: n
1023 class(*), intent(inout), target :: x(:,:,:)
1024 type(c_ptr), intent(inout) :: x_d
1025 type(c_ptr) :: ptr_h
1026 integer(c_size_t) :: s
1027
1028 if (c_associated(x_d)) then
1029 call neko_error('Device pointer already associated')
1030 end if
1031
1032 select type (x)
1033 type is (integer)
1034 s = n * int(4, c_size_t)
1035 ptr_h = c_loc(x)
1036 type is (integer(i8))
1037 s = n * int(8, c_size_t)
1038 ptr_h = c_loc(x)
1039 type is (real)
1040 s = n * int(4, c_size_t)
1041 ptr_h = c_loc(x)
1042 type is (double precision)
1043 s = n * int(8, c_size_t)
1044 ptr_h = c_loc(x)
1045 class default
1046 call neko_error('Unknown Fortran type')
1047 end select
1048
1049 call device_map_common(ptr_h, x_d, s)
1050 call device_associate(x, x_d, n)
1051
1052 end subroutine device_map_r3
1053
1055 subroutine device_map_r4(x, x_d, n)
1056 integer, intent(in) :: n
1057 class(*), intent(inout), target :: x(:,:,:,:)
1058 type(c_ptr), intent(inout) :: x_d
1059 type(c_ptr) :: ptr_h
1060 integer(c_size_t) :: s
1061
1062 if (c_associated(x_d)) then
1063 call neko_error('Device pointer already associated')
1064 end if
1065
1066 select type (x)
1067 type is (integer)
1068 s = n * int(4, c_size_t)
1069 ptr_h = c_loc(x)
1070 type is (integer(i8))
1071 s = n * int(8, c_size_t)
1072 ptr_h = c_loc(x)
1073 type is (real)
1074 s = n * int(4, c_size_t)
1075 ptr_h = c_loc(x)
1076 type is (double precision)
1077 s = n * int(8, c_size_t)
1078 ptr_h = c_loc(x)
1079 class default
1080 call neko_error('Unknown Fortran type')
1081 end select
1082
1083 call device_map_common(ptr_h, x_d, s)
1084 call device_associate(x, x_d, n)
1085
1086 end subroutine device_map_r4
1087
1089 subroutine device_unmap_r1(x, x_d)
1090 class(*), intent(inout), target :: x(:)
1091 type(c_ptr), intent(inout) :: x_d
1092 type(c_ptr) :: dev
1093 logical :: mapped
1094
1095 ! Whether dev has a non-null address, meaning that x is mapped.
1096 mapped = device_associated(x)
1097
1098 ! Repeated calls to this routine do nothing
1099 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1100 return
1101 end if
1102
1103 ! Device pointer associated with x, should be same as x_d if mapped
1104 if (mapped) then
1105 dev = device_get_ptr(x)
1106 else
1107 dev = c_null_ptr
1108 end if
1109
1110 ! Error if:
1111 ! 1) x is not mapped to a device pointer, but x_d is not null.
1112 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1113 ! 3) x is mapped to a device pointer that is not x_d.
1114 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1115 (.not. c_associated(dev, x_d))) then
1116 call neko_error('Inconsistent host/device mapping state in ' // &
1117 'device_unmap')
1118 end if
1119
1120 call device_deassociate(x)
1121 call device_free(x_d)
1122
1123 end subroutine device_unmap_r1
1124
1126 subroutine device_unmap_r2(x, x_d)
1127 class(*), intent(inout), target :: x(:,:)
1128 type(c_ptr), intent(inout) :: x_d
1129 type(c_ptr) :: dev
1130 logical :: mapped
1131
1132 ! Whether dev has a non-null address, meaning that x is mapped.
1133 mapped = device_associated(x)
1134
1135 ! Repeated calls to this routine do nothing
1136 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1137 return
1138 end if
1139
1140 ! Device pointer associated with x, should be same as x_d if mapped
1141 if (mapped) then
1142 dev = device_get_ptr(x)
1143 else
1144 dev = c_null_ptr
1145 end if
1146
1147 ! Error if:
1148 ! 1) x is not mapped to a device pointer, but x_d is not null.
1149 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1150 ! 3) x is mapped to a device pointer that is not x_d.
1151 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1152 (.not. c_associated(dev, x_d))) then
1153 call neko_error('Inconsistent host/device mapping state in ' // &
1154 'device_unmap')
1155 end if
1156
1157 call device_deassociate(x)
1158 call device_free(x_d)
1159
1160 end subroutine device_unmap_r2
1161
1163 subroutine device_unmap_r3(x, x_d)
1164 class(*), intent(inout), target :: x(:,:,:)
1165 type(c_ptr), intent(inout) :: x_d
1166 type(c_ptr) :: dev
1167 logical :: mapped
1168
1169 ! Whether dev has a non-null address, meaning that x is mapped.
1170 mapped = device_associated(x)
1171
1172 ! Repeated calls to this routine do nothing
1173 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1174 return
1175 end if
1176
1177 ! Device pointer associated with x, should be same as x_d if mapped
1178 if (mapped) then
1179 dev = device_get_ptr(x)
1180 else
1181 dev = c_null_ptr
1182 end if
1183
1184 ! Error if:
1185 ! 1) x is not mapped to a device pointer, but x_d is not null.
1186 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1187 ! 3) x is mapped to a device pointer that is not x_d.
1188 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1189 (.not. c_associated(dev, x_d))) then
1190 call neko_error('Inconsistent host/device mapping state in ' // &
1191 'device_unmap')
1192 end if
1193
1194 call device_deassociate(x)
1195 call device_free(x_d)
1196
1197 end subroutine device_unmap_r3
1198
1200 subroutine device_unmap_r4(x, x_d)
1201 class(*), intent(inout), target :: x(:,:,:,:)
1202 type(c_ptr), intent(inout) :: x_d
1203 type(c_ptr) :: dev
1204 logical :: mapped
1205
1206 ! Whether dev has a non-null address, meaning that x is mapped.
1207 mapped = device_associated(x)
1208
1209 ! Repeated calls to this routine do nothing
1210 if ((.not. mapped) .and. (.not. c_associated(x_d))) then
1211 return
1212 end if
1213
1214 ! Device pointer associated with x, should be same as x_d if mapped
1215 if (mapped) then
1216 dev = device_get_ptr(x)
1217 else
1218 dev = c_null_ptr
1219 end if
1220
1221 ! Error if:
1222 ! 1) x is not mapped to a device pointer, but x_d is not null.
1223 ! 2) x_d is not a valid pointer, but x is mapped to some pointer.
1224 ! 3) x is mapped to a device pointer that is not x_d.
1225 if ((.not. mapped) .or. (.not. c_associated(x_d)) .or. &
1226 (.not. c_associated(dev, x_d))) then
1227 call neko_error('Inconsistent host/device mapping state in ' // &
1228 'device_unmap')
1229 end if
1230
1231 call device_deassociate(x)
1232 call device_free(x_d)
1233
1234 end subroutine device_unmap_r4
1235
1237 function device_associated_r1(x) result(assoc)
1238 class(*), intent(inout), target :: x(:)
1239 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1240 logical :: assoc
1241
1242 select type (x)
1243 type is (integer)
1244 htbl_ptr_h%ptr = c_loc(x)
1245 type is (integer(i8))
1246 htbl_ptr_h%ptr = c_loc(x)
1247 type is (real)
1248 htbl_ptr_h%ptr = c_loc(x)
1249 type is (double precision)
1250 htbl_ptr_h%ptr = c_loc(x)
1251 class default
1252 call neko_error('Unknown Fortran type')
1253 end select
1254
1255 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1256 assoc = .true.
1257 else
1258 assoc = .false.
1259 end if
1260
1261 end function device_associated_r1
1262
1264 function device_associated_r2(x) result(assoc)
1265 class(*), intent(inout), target :: x(:,:)
1266 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1267 logical :: assoc
1268
1269 select type (x)
1270 type is (integer)
1271 htbl_ptr_h%ptr = c_loc(x)
1272 type is (integer(i8))
1273 htbl_ptr_h%ptr = c_loc(x)
1274 type is (real)
1275 htbl_ptr_h%ptr = c_loc(x)
1276 type is (double precision)
1277 htbl_ptr_h%ptr = c_loc(x)
1278 class default
1279 call neko_error('Unknown Fortran type')
1280 end select
1281
1282 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1283 assoc = .true.
1284 else
1285 assoc = .false.
1286 end if
1287
1288 end function device_associated_r2
1289
1291 function device_associated_r3(x) result(assoc)
1292 class(*), intent(inout), target :: x(:,:,:)
1293 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1294 logical :: assoc
1295
1296 select type (x)
1297 type is (integer)
1298 htbl_ptr_h%ptr = c_loc(x)
1299 type is (integer(i8))
1300 htbl_ptr_h%ptr = c_loc(x)
1301 type is (real)
1302 htbl_ptr_h%ptr = c_loc(x)
1303 type is (double precision)
1304 htbl_ptr_h%ptr = c_loc(x)
1305 class default
1306 call neko_error('Unknown Fortran type')
1307 end select
1308
1309 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1310 assoc = .true.
1311 else
1312 assoc = .false.
1313 end if
1314
1315 end function device_associated_r3
1316
1318 function device_associated_r4(x) result(assoc)
1319 class(*), intent(inout), target :: x(:,:,:,:)
1320 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1321 logical :: assoc
1322
1323 select type (x)
1324 type is (integer)
1325 htbl_ptr_h%ptr = c_loc(x)
1326 type is (integer(i8))
1327 htbl_ptr_h%ptr = c_loc(x)
1328 type is (real)
1329 htbl_ptr_h%ptr = c_loc(x)
1330 type is (double precision)
1331 htbl_ptr_h%ptr = c_loc(x)
1332 class default
1333 call neko_error('Unknown Fortran type')
1334 end select
1335
1336 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1337 assoc = .true.
1338 else
1339 assoc = .false.
1340 end if
1341
1342 end function device_associated_r4
1343
1346 class(*), intent(in), target :: x(:)
1347 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1348 type(c_ptr) :: device_get_ptr_r1
1349
1350 device_get_ptr_r1 = c_null_ptr
1351
1352 select type (x)
1353 type is (integer)
1354 htbl_ptr_h%ptr = c_loc(x)
1355 type is (integer(i8))
1356 htbl_ptr_h%ptr = c_loc(x)
1357 type is (real)
1358 htbl_ptr_h%ptr = c_loc(x)
1359 type is (double precision)
1360 htbl_ptr_h%ptr = c_loc(x)
1361 class default
1362 call neko_error('Unknown Fortran type')
1363 end select
1364
1365 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1366 device_get_ptr_r1 = htbl_ptr_d%ptr
1367 else
1368 call neko_error('Array not associated with device')
1369 end if
1370 end function device_get_ptr_r1
1371
1374 class(*), intent(in), target :: x(:,:)
1375 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1376 type(c_ptr) :: device_get_ptr_r2
1377
1378 device_get_ptr_r2 = c_null_ptr
1379
1380 select type (x)
1381 type is (integer)
1382 htbl_ptr_h%ptr = c_loc(x)
1383 type is (integer(i8))
1384 htbl_ptr_h%ptr = c_loc(x)
1385 type is (real)
1386 htbl_ptr_h%ptr = c_loc(x)
1387 type is (double precision)
1388 htbl_ptr_h%ptr = c_loc(x)
1389 class default
1390 call neko_error('Unknown Fortran type')
1391 end select
1392
1393 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1394 device_get_ptr_r2 = htbl_ptr_d%ptr
1395 else
1396 call neko_error('Array not associated with device')
1397 end if
1398 end function device_get_ptr_r2
1399
1402 class(*), intent(in), target :: x(:,:,:)
1403 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1404 type(c_ptr) :: device_get_ptr_r3
1405
1406 device_get_ptr_r3 = c_null_ptr
1407
1408 select type (x)
1409 type is (integer)
1410 htbl_ptr_h%ptr = c_loc(x)
1411 type is (integer(i8))
1412 htbl_ptr_h%ptr = c_loc(x)
1413 type is (real)
1414 htbl_ptr_h%ptr = c_loc(x)
1415 type is (double precision)
1416 htbl_ptr_h%ptr = c_loc(x)
1417 class default
1418 call neko_error('Unknown Fortran type')
1419 end select
1420
1421 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1422 device_get_ptr_r3 = htbl_ptr_d%ptr
1423 else
1424 call neko_error('Array not associated with device')
1425 end if
1426 end function device_get_ptr_r3
1427
1430 class(*), intent(in), target :: x(:,:,:,:)
1431 type(h_cptr_t) :: htbl_ptr_h, htbl_ptr_d
1432 type(c_ptr) :: device_get_ptr_r4
1433
1434 device_get_ptr_r4 = c_null_ptr
1435
1436 select type (x)
1437 type is (integer)
1438 htbl_ptr_h%ptr = c_loc(x)
1439 type is (integer(i8))
1440 htbl_ptr_h%ptr = c_loc(x)
1441 type is (real)
1442 htbl_ptr_h%ptr = c_loc(x)
1443 type is (double precision)
1444 htbl_ptr_h%ptr = c_loc(x)
1445 class default
1446 call neko_error('Unknown Fortran type')
1447 end select
1448
1449 if (device_addrtbl%get(htbl_ptr_h, htbl_ptr_d) .eq. 0) then
1450 device_get_ptr_r4 = htbl_ptr_d%ptr
1451 else
1452 call neko_error('Array not associated with device')
1453 end if
1454 end function device_get_ptr_r4
1455
1458#ifdef HAVE_HIP
1459 if (hipdevicesynchronize() .ne. hipsuccess) then
1460 call neko_error('Error during device sync')
1461 end if
1462#elif HAVE_CUDA
1463 if (cudadevicesynchronize() .ne. cudasuccess) then
1464 call neko_error('Error during device sync')
1465 end if
1466#elif HAVE_OPENCL
1467 if (clfinish(glb_cmd_queue) .ne. cl_success) then
1468 call neko_error('Error during device sync')
1469 end if
1470#elif HAVE_METAL
1471 if (metaldevicesynchronize() .ne. metalsuccess) then
1472 call neko_error('Error during device sync')
1473 end if
1474#endif
1475 end subroutine device_sync_device
1476
1478 subroutine device_sync_stream(stream)
1479 type(c_ptr), intent(in) :: stream
1480#ifdef HAVE_HIP
1481 if (hipstreamsynchronize(stream) .ne. hipsuccess) then
1482 call neko_error('Error during stream sync')
1483 end if
1484#elif HAVE_CUDA
1485 if (cudastreamsynchronize(stream) .ne. cudasuccess) then
1486 call neko_error('Error during stream sync')
1487 end if
1488#elif HAVE_OPENCL
1489 if (clfinish(stream) .ne. cl_success) then
1490 call neko_error('Error during stream sync')
1491 end if
1492#elif HAVE_METAL
1493 if (metalstreamsynchronize(stream) .ne. metalsuccess) then
1494 call neko_error('Error during stream sync')
1495 end if
1496#endif
1497 end subroutine device_sync_stream
1498
1500 subroutine device_stream_create(stream, flags)
1501 type(c_ptr), intent(inout) :: stream
1502 integer, optional :: flags
1503 integer :: ierr
1504#ifdef HAVE_HIP
1505 if (present(flags)) then
1506 if (hipstreamcreatewithflags(stream, flags) .ne. hipsuccess) then
1507 call neko_error('Error during stream create (w. flags)')
1508 end if
1509 else
1510 if (hipstreamcreate(stream) .ne. hipsuccess) then
1511 call neko_error('Error during stream create')
1512 end if
1513 end if
1514#elif HAVE_CUDA
1515 if (present(flags)) then
1516 if (cudastreamcreatewithflags(stream, flags) .ne. cudasuccess) then
1517 call neko_error('Error during stream create (w. flags)')
1518 end if
1519 else
1520 if (cudastreamcreate(stream) .ne. cudasuccess) then
1521 call neko_error('Error during stream create')
1522 end if
1523 end if
1524#elif HAVE_OPENCL
1525 stream = clcreatecommandqueue(glb_ctx, glb_device_id, 0_i8, ierr)
1526 if (ierr .ne. cl_success) then
1527 call neko_error('Error during stream create')
1528 end if
1529#elif HAVE_METAL
1530 if (metalstreamcreate(stream) .ne. metalsuccess) then
1531 call neko_error('Error during stream create')
1532 end if
1533#endif
1534 end subroutine device_stream_create
1535
1537 subroutine device_stream_create_with_priority(stream, flags, prio)
1538 type(c_ptr), intent(inout) :: stream
1539 integer, intent(in) :: flags, prio
1540#ifdef HAVE_HIP
1541 if (hipstreamcreatewithpriority(stream, flags, prio) .ne. hipsuccess) then
1542 call neko_error('Error during stream create (w. priority)')
1543 end if
1544#elif HAVE_CUDA
1545 if (cudastreamcreatewithpriority(stream, flags, prio) .ne. cudasuccess) then
1546 call neko_error('Error during stream create (w. priority)')
1547 end if
1548#elif HAVE_OPENCL
1549 call neko_error('Not implemented yet')
1550#elif HAVE_METAL
1551 ! Metal command queues have no priority, create a plain queue
1552 if (metalstreamcreate(stream) .ne. metalsuccess) then
1553 call neko_error('Error during stream create (w. priority)')
1554 end if
1555#endif
1557
1559 subroutine device_stream_destroy(stream)
1560 type(c_ptr), intent(inout) :: stream
1561#ifdef HAVE_HIP
1562 if (hipstreamdestroy(stream) .ne. hipsuccess) then
1563 call neko_error('Error during stream destroy')
1564 end if
1565#elif HAVE_CUDA
1566 if (cudastreamdestroy(stream) .ne. cudasuccess) then
1567 call neko_error('Error during stream destroy')
1568 end if
1569#elif HAVE_OPENCL
1570 if (clreleasecommandqueue(stream) .ne. cl_success) then
1571 call neko_error('Error during stream destroy')
1572 end if
1573#elif HAVE_METAL
1574 if (metalstreamdestroy(stream) .ne. metalsuccess) then
1575 call neko_error('Error during stream destroy')
1576 end if
1577#endif
1578 end subroutine device_stream_destroy
1579
1581 subroutine device_stream_wait_event(stream, event, flags)
1582 type(c_ptr), intent(in) :: stream
1583 type(c_ptr), target, intent(in) :: event
1584 integer :: flags
1585#ifdef HAVE_HIP
1586 if (hipstreamwaitevent(stream, event, flags) .ne. hipsuccess) then
1587 call neko_error('Error during stream sync')
1588 end if
1589#elif HAVE_CUDA
1590 if (cudastreamwaitevent(stream, event, flags) .ne. cudasuccess) then
1591 call neko_error('Error during stream sync')
1592 end if
1593#elif HAVE_OPENCL
1594 if (clenqueuebarrier(stream) .ne. cl_success) then
1595 call neko_error('Error during barrier')
1596 end if
1597 if (clenqueuewaitforevents(stream, 1, c_loc(event)) .ne. cl_success) then
1598 call neko_error('Error during stream sync')
1599 end if
1600#elif HAVE_METAL
1601 if (metalstreamwaitevent(stream, event) .ne. metalsuccess) then
1602 call neko_error('Error during stream sync')
1603 end if
1604#endif
1605 end subroutine device_stream_wait_event
1606
1609#if HAVE_CUDA
1610 if (cudaprofilerstart() .ne. cudasuccess) then
1611 call neko_error('Error starting profiler')
1612 end if
1613#endif
1614 end subroutine device_profiler_start
1615
1618#if HAVE_CUDA
1619 if (cudaprofilerstop() .ne. cudasuccess) then
1620 call neko_error('Error stopping profiler')
1621 end if
1622#endif
1623 end subroutine device_profiler_stop
1624
1626 subroutine device_event_create(event, flags)
1627 type(c_ptr), intent(inout) :: event
1628 integer, optional :: flags
1629 integer :: ierr
1630#ifdef HAVE_HIP
1631 if (present(flags)) then
1632 if (hipeventcreatewithflags(event, flags) .ne. hipsuccess) then
1633 call neko_error('Error during event create (w. flags)')
1634 end if
1635 else
1636 if (hipeventcreate(event) .ne. hipsuccess) then
1637 call neko_error('Error during event create')
1638 end if
1639 end if
1640#elif HAVE_CUDA
1641 if (present(flags)) then
1642 if (cudaeventcreatewithflags(event, flags) .ne. cudasuccess) then
1643 call neko_error('Error during event create (w. flags)')
1644 end if
1645 else
1646 if (cudaeventcreate(event) .ne. cudasuccess) then
1647 call neko_error('Error during event create')
1648 end if
1649 end if
1650#elif HAVE_OPENCL
1651 event = c_null_ptr
1652#elif HAVE_METAL
1653 if (metaleventcreate(event) .ne. metalsuccess) then
1654 call neko_error('Error during event create')
1655 end if
1656#endif
1657 end subroutine device_event_create
1658
1660 subroutine device_event_destroy(event)
1661 type(c_ptr), intent(inout) :: event
1662#ifdef HAVE_HIP
1663 if (hipeventdestroy(event) .ne. hipsuccess) then
1664 call neko_error('Error during event destroy')
1665 end if
1666#elif HAVE_CUDA
1667 if (cudaeventdestroy(event) .ne. cudasuccess) then
1668 call neko_error('Error during event destroy')
1669 end if
1670#elif HAVE_OPENCL
1671 event = c_null_ptr
1672#elif HAVE_METAL
1673 if (metaleventdestroy(event) .ne. metalsuccess) then
1674 call neko_error('Error during event destroy')
1675 end if
1676 event = c_null_ptr
1677#endif
1678 end subroutine device_event_destroy
1679
1681 subroutine device_event_record(event, stream)
1682 type(c_ptr), target, intent(in) :: event
1683 type(c_ptr), intent(in) :: stream
1684#ifdef HAVE_HIP
1685 if (hipeventrecord(event, stream) .ne. hipsuccess) then
1686 call neko_error('Error recording an event')
1687 end if
1688#elif HAVE_CUDA
1689 if (cudaeventrecord(event, stream) .ne. cudasuccess) then
1690 call neko_error('Error recording an event')
1691 end if
1692#elif HAVE_OPENCL
1693 if (clenqueuemarker(stream, c_loc(event)) .ne. cl_success) then
1694 call neko_error('Error recording an event')
1695 end if
1696#elif HAVE_METAL
1697 if (metaleventrecord(event, stream) .ne. metalsuccess) then
1698 call neko_error('Error recording an event')
1699 end if
1700#endif
1701 end subroutine device_event_record
1702
1704 subroutine device_event_sync(event)
1705 type(c_ptr), target, intent(in) :: event
1706#ifdef HAVE_HIP
1707 if (hipeventsynchronize(event) .ne. hipsuccess) then
1708 call neko_error('Error during event sync')
1709 end if
1710#elif HAVE_CUDA
1711 if (cudaeventsynchronize(event) .ne. cudasuccess) then
1712 call neko_error('Error during event sync')
1713 end if
1714#elif HAVE_OPENCL
1715 if (c_associated(event)) then
1716 if (clwaitforevents(1, c_loc(event)) .ne. cl_success) then
1717 call neko_error('Error during event sync')
1718 end if
1719 end if
1720#elif HAVE_METAL
1721 if (c_associated(event)) then
1722 if (metaleventsynchronize(event) .ne. metalsuccess) then
1723 call neko_error('Error during event sync')
1724 end if
1725 end if
1726#endif
1727 end subroutine device_event_sync
1728
1729end module device
double real
Number of streaming multiprocessors of the current device (0 if unknown), see device/cuda/props....
Total memory of the current device in bytes (0 if unknown), see device/cuda/props....
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
Number of compute units of the current device (0 if unknown), see device/hip/props....
Definition hip_intf.F90:198
Total memory of the current device in bytes (0 if unknown), see device/hip/props.hip.
Definition hip_intf.F90:206
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:1682
subroutine device_associate_r4(x, x_d, n)
Associate a Fortran rank 4 array to a (allocated) device pointer.
Definition device.F90:786
subroutine, public device_event_sync(event)
Synchronize an event.
Definition device.F90:1705
subroutine device_associate_r1(x, x_d, n)
Associate a Fortran rank 1 array to a (allocated) device pointer.
Definition device.F90:676
subroutine, public device_finalize
Definition device.F90:164
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:1430
integer function, public device_mp_count()
Return the number of multiprocessors (SMs on NVIDIA, CUs on AMD, compute units on OpenCL,...
Definition device.F90:217
type(c_ptr) function device_get_ptr_r1(x)
Return the device pointer for an associated Fortran rank 1 array.
Definition device.F90:1346
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:1022
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:1292
subroutine device_unmap_r4(x, x_d)
Unmap a Fortran rank 4 array from a device (deassociate and free)
Definition device.F90:1201
subroutine, public device_profiler_stop()
Stop device profiling.
Definition device.F90:1618
subroutine device_deassociate_r3(x)
Deassociate a Fortran rank 3 array from a device pointer.
Definition device.F90:871
subroutine, public device_sync_stream(stream)
Synchronize a device stream.
Definition device.F90:1479
type(c_ptr) function device_get_ptr_r3(x)
Return the device pointer for an associated Fortran rank 3 array.
Definition device.F90:1402
subroutine device_unmap_r2(x, x_d)
Unmap a Fortran rank 2 array from a device (deassociate and free)
Definition device.F90:1127
subroutine, public device_profiler_start()
Start device profiling.
Definition device.F90:1609
subroutine device_map_r2(x, x_d, n)
Map a Fortran rank 2 array to a device (allocate and associate)
Definition device.F90:988
subroutine device_memcpy_r2(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 2 arrays)
Definition device.F90:393
subroutine device_map_r4(x, x_d, n)
Map a Fortran rank 4 array to a device (allocate and associate)
Definition device.F90:1056
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:281
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:509
subroutine device_memcpy_common(ptr_h, x_d, s, dir, sync_device, stream)
Copy data between host and device.
Definition device.F90:538
subroutine, public device_event_destroy(event)
Destroy a device event.
Definition device.F90:1661
subroutine, public device_alloc(x_d, s)
Allocate memory on the device.
Definition device.F90:250
subroutine device_associate_r2(x, x_d, n)
Associate a Fortran rank 2 array to a (allocated) device pointer.
Definition device.F90:713
subroutine, public device_stream_create_with_priority(stream, flags, prio)
Create a device stream/command queue with priority.
Definition device.F90:1538
subroutine, public device_stream_create(stream, flags)
Create a device stream/command queue.
Definition device.F90:1501
subroutine device_deassociate_r4(x)
Deassociate a Fortran rank 4 array from a device pointer.
Definition device.F90:895
subroutine device_sync_device()
Synchronize the device.
Definition device.F90:1458
subroutine device_memcpy_r4(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 4 arrays)
Definition device.F90:469
subroutine, public device_stream_wait_event(stream, event, flags)
Synchronize a device stream with an event.
Definition device.F90:1582
subroutine device_map_r1(x, x_d, n)
Map a Fortran rank 1 array to a device (allocate and associate)
Definition device.F90:954
subroutine device_associate_r3(x, x_d, n)
Associate a Fortran rank 3 array to a (allocated) device pointer.
Definition device.F90:750
subroutine device_unmap_r1(x, x_d)
Unmap a Fortran rank 1 array from a device (deassociate and free)
Definition device.F90:1090
subroutine device_memcpy_r1(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 1 arrays)
Definition device.F90:355
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:1627
integer function, public device_count()
Return the number of available devices.
Definition device.F90:198
subroutine, public device_name(name)
Definition device.F90:183
logical function device_associated_r4(x)
Check if a Fortran rank 4 array is assoicated with a device pointer.
Definition device.F90:1319
logical function device_associated_r2(x)
Check if a Fortran rank 2 array is assoicated with a device pointer.
Definition device.F90:1265
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
integer(kind=i8) function, public device_total_mem()
Return the total memory of the current device in bytes, or 0 if the backend cannot tell.
Definition device.F90:235
subroutine device_map_common(ptr_h, x_d, s)
Allocate device memory backing a mapped host array.
Definition device.F90:922
type(c_ptr) function device_get_ptr_r2(x)
Return the device pointer for an associated Fortran rank 2 array.
Definition device.F90:1374
subroutine device_unmap_r3(x, x_d)
Unmap a Fortran rank 3 array from a device (deassociate and free)
Definition device.F90:1164
subroutine device_deassociate_r1(x)
Deassociate a Fortran rank 1 array from a device pointer.
Definition device.F90:823
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:847
subroutine, public device_init
Definition device.F90:139
logical function device_associated_r1(x)
Check if a Fortran rank 1 array is assoicated with a device pointer.
Definition device.F90:1238
subroutine, public device_memset(x_d, v, s, sync, strm)
Set memory on the device to a value.
Definition device.F90:306
subroutine device_memcpy_r3(x, x_d, n, dir, sync, strm)
Copy data between host and device (rank 3 arrays)
Definition device.F90:431
subroutine, public device_stream_destroy(stream)
Destroy a device stream/command queue.
Definition device.F90:1560
Fortran HIP interface.
Definition hip_intf.F90:34
subroutine hip_device_name(name)
Definition hip_intf.F90:357
@ 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:306
subroutine hip_finalize(glb_cmd_queue, aux_cmd_queue)
Definition hip_intf.F90:328
integer function hip_device_count()
Return the number of available HIP devices.
Definition hip_intf.F90:374
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)
integer function opencl_device_mp_count()
Return the number of compute units of the current device (CL_DEVICE_MAX_COMPUTE_UNITS),...
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)
integer(kind=i8) function opencl_device_total_mem()
Return the global memory size of the current device in bytes (CL_DEVICE_GLOBAL_MEM_SIZE),...
OpenCL JIT program library.
Definition prgm_lib.F90:2
subroutine, public opencl_prgm_lib_release
Definition prgm_lib.F90:192
Utilities.
Definition utils.f90:35
C pointer based hash table.
Definition htable.f90:162