LCOV - code coverage report
Current view: top level - src/offload - offload_api.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 69.2 % 65 45
Test Date: 2026-07-25 06:35:44 Functions: 60.0 % 15 9

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: BSD-3-Clause                                                          !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Fortran API for the offload package, which is written in C.
      10              : !> \author Ole Schuett
      11              : ! **************************************************************************************************
      12              : MODULE offload_api
      13              :    USE ISO_C_BINDING,                   ONLY: &
      14              :         C_ASSOCIATED, C_CHAR, C_FUNLOC, C_FUNPTR, C_F_POINTER, C_INT, C_NULL_CHAR, C_NULL_PTR, &
      15              :         C_PTR, C_SIZE_T
      16              :    USE kinds,                           ONLY: dp,&
      17              :                                               int_8
      18              :    USE message_passing,                 ONLY: mp_comm_type
      19              : #include "../base/base_uses.f90"
      20              : 
      21              :    IMPLICIT NONE
      22              : 
      23              :    PRIVATE
      24              : 
      25              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'offload_api'
      26              : 
      27              :    PUBLIC :: offload_init
      28              :    PUBLIC :: offload_get_device_count
      29              :    PUBLIC :: offload_set_chosen_device, offload_get_chosen_device, offload_activate_chosen_device
      30              :    PUBLIC :: offload_timeset, offload_timestop, offload_mem_info
      31              :    PUBLIC :: offload_buffer_type, offload_create_buffer, offload_free_buffer
      32              :    PUBLIC :: offload_malloc_pinned_mem, offload_free_pinned_mem
      33              :    PUBLIC :: offload_mempool_stats_print
      34              : 
      35              :    TYPE offload_buffer_type
      36              :       REAL(KIND=dp), DIMENSION(:), CONTIGUOUS, POINTER :: host_buffer => Null()
      37              :       TYPE(C_PTR)                          :: c_ptr = C_NULL_PTR
      38              :    END TYPE offload_buffer_type
      39              : 
      40              : CONTAINS
      41              : 
      42              : ! **************************************************************************************************
      43              : !> \brief allocate pinned memory.
      44              : !> \param buffer address of the buffer
      45              : !> \param length length of the buffer
      46              : !> \return 0
      47              : ! **************************************************************************************************
      48            0 :    FUNCTION offload_malloc_pinned_mem(buffer, length) RESULT(res)
      49              :       TYPE(C_PTR)                                        :: buffer
      50              :       INTEGER(C_SIZE_T), VALUE                           :: length
      51              :       INTEGER                                            :: res
      52              : 
      53              :       INTERFACE
      54              :          FUNCTION offload_malloc_pinned_mem_c(buffer, length) &
      55              :             BIND(C, name="offload_host_malloc")
      56              :             IMPORT C_SIZE_T, C_PTR, C_INT
      57              :             TYPE(C_PTR)              :: buffer
      58              :             INTEGER(C_SIZE_T), VALUE :: length
      59              :             INTEGER(KIND=C_INT)                :: offload_malloc_pinned_mem_c
      60              :          END FUNCTION offload_malloc_pinned_mem_c
      61              :       END INTERFACE
      62              : 
      63            0 :       res = offload_malloc_pinned_mem_c(buffer, length)
      64            0 :    END FUNCTION offload_malloc_pinned_mem
      65              : 
      66              : ! **************************************************************************************************
      67              : !> \brief free pinned memory
      68              : !> \param buffer address of the buffer
      69              : !> \return 0
      70              : ! **************************************************************************************************
      71            0 :    FUNCTION offload_free_pinned_mem(buffer) RESULT(res)
      72              :       TYPE(C_PTR), VALUE                                 :: buffer
      73              :       INTEGER                                            :: res
      74              : 
      75              :       INTERFACE
      76              :          FUNCTION offload_free_pinned_mem_c(buffer) &
      77              :             BIND(C, name="offload_host_free")
      78              :             IMPORT C_PTR, C_INT
      79              :             INTEGER(KIND=C_INT)                :: offload_free_pinned_mem_c
      80              :             TYPE(C_PTR), VALUE            :: buffer
      81              :          END FUNCTION offload_free_pinned_mem_c
      82              :       END INTERFACE
      83              : 
      84            0 :       res = offload_free_pinned_mem_c(buffer)
      85            0 :    END FUNCTION offload_free_pinned_mem
      86              : 
      87              : ! **************************************************************************************************
      88              : !> \brief Initialize runtime.
      89              : !> \return ...
      90              : !> \author Rocco Meli
      91              : ! **************************************************************************************************
      92        10486 :    SUBROUTINE offload_init()
      93              :       INTERFACE
      94              :          SUBROUTINE offload_init_c() &
      95              :             BIND(C, name="offload_init")
      96              :          END SUBROUTINE offload_init_c
      97              :       END INTERFACE
      98              : 
      99        10486 :       CALL offload_init_c()
     100              : 
     101        10486 :    END SUBROUTINE offload_init
     102              : 
     103              : ! **************************************************************************************************
     104              : !> \brief Returns the number of available devices.
     105              : !> \return ...
     106              : !> \author Ole Schuett
     107              : ! **************************************************************************************************
     108        10490 :    FUNCTION offload_get_device_count() RESULT(count)
     109              :       INTEGER                                            :: count
     110              : 
     111              :       INTERFACE
     112              :          FUNCTION offload_get_device_count_c() &
     113              :             BIND(C, name="offload_get_device_count")
     114              :             IMPORT :: C_INT
     115              :             INTEGER(KIND=C_INT)                :: offload_get_device_count_c
     116              :          END FUNCTION offload_get_device_count_c
     117              :       END INTERFACE
     118              : 
     119        10490 :       count = offload_get_device_count_c()
     120              : 
     121        10490 :    END FUNCTION offload_get_device_count
     122              : 
     123              : ! **************************************************************************************************
     124              : !> \brief Selects the chosen device to be used.
     125              : !> \param device_id ...
     126              : !> \author Ole Schuett
     127              : ! **************************************************************************************************
     128            0 :    SUBROUTINE offload_set_chosen_device(device_id)
     129              :       INTEGER, INTENT(IN)                                :: device_id
     130              : 
     131              :       INTERFACE
     132              :          SUBROUTINE offload_set_chosen_device_c(device_id) &
     133              :             BIND(C, name="offload_set_chosen_device")
     134              :             IMPORT :: C_INT
     135              :             INTEGER(KIND=C_INT), VALUE                :: device_id
     136              :          END SUBROUTINE offload_set_chosen_device_c
     137              :       END INTERFACE
     138              : 
     139            0 :       CALL offload_set_chosen_device_c(device_id=device_id)
     140              : 
     141            0 :    END SUBROUTINE offload_set_chosen_device
     142              : 
     143              : ! **************************************************************************************************
     144              : !> \brief Returns the chosen device.
     145              : !> \return ...
     146              : !> \author Ole Schuett
     147              : ! **************************************************************************************************
     148            0 :    FUNCTION offload_get_chosen_device() RESULT(device_id)
     149              :       INTEGER                                            :: device_id
     150              : 
     151              :       INTERFACE
     152              :          FUNCTION offload_get_chosen_device_c() &
     153              :             BIND(C, name="offload_get_chosen_device")
     154              :             IMPORT :: C_INT
     155              :             INTEGER(KIND=C_INT)                :: offload_get_chosen_device_c
     156              :          END FUNCTION offload_get_chosen_device_c
     157              :       END INTERFACE
     158              : 
     159            0 :       device_id = offload_get_chosen_device_c()
     160              : 
     161            0 :       IF (device_id < 0) THEN
     162            0 :          CPABORT("No offload device has been chosen.")
     163              :       END IF
     164              : 
     165            0 :    END FUNCTION offload_get_chosen_device
     166              : 
     167              : ! **************************************************************************************************
     168              : !> \brief Activates the device selected via offload_set_chosen_device()
     169              : !> \author Ole Schuett
     170              : ! **************************************************************************************************
     171      2278401 :    SUBROUTINE offload_activate_chosen_device()
     172              : 
     173              :       INTERFACE
     174              :          SUBROUTINE offload_activate_chosen_device_c() &
     175              :             BIND(C, name="offload_activate_chosen_device")
     176              :          END SUBROUTINE offload_activate_chosen_device_c
     177              :       END INTERFACE
     178              : 
     179      2278401 :       CALL offload_activate_chosen_device_c()
     180              : 
     181      2278401 :    END SUBROUTINE offload_activate_chosen_device
     182              : 
     183              : ! **************************************************************************************************
     184              : !> \brief Starts a timing range.
     185              : !> \param routineN ...
     186              : !> \author Ole Schuett
     187              : ! **************************************************************************************************
     188   2015688125 :    SUBROUTINE offload_timeset(routineN)
     189              :       CHARACTER(LEN=*), INTENT(IN)                       :: routineN
     190              : 
     191              :       INTERFACE
     192              :          SUBROUTINE offload_timeset_c(message) BIND(C, name="offload_timeset")
     193              :             IMPORT :: C_CHAR
     194              :             CHARACTER(kind=C_CHAR), DIMENSION(*), INTENT(IN) :: message
     195              :          END SUBROUTINE offload_timeset_c
     196              :       END INTERFACE
     197              : 
     198   2015688125 :       CALL offload_timeset_c(TRIM(routineN)//C_NULL_CHAR)
     199              : 
     200   2015688125 :    END SUBROUTINE offload_timeset
     201              : 
     202              : ! **************************************************************************************************
     203              : !> \brief  Ends a timing range.
     204              : !> \author Ole Schuett
     205              : ! **************************************************************************************************
     206   2015688125 :    SUBROUTINE offload_timestop()
     207              : 
     208              :       INTERFACE
     209              :          SUBROUTINE offload_timestop_c() BIND(C, name="offload_timestop")
     210              :          END SUBROUTINE offload_timestop_c
     211              :       END INTERFACE
     212              : 
     213   2015688125 :       CALL offload_timestop_c()
     214              : 
     215   2015688125 :    END SUBROUTINE offload_timestop
     216              : 
     217              : ! **************************************************************************************************
     218              : !> \brief Gets free and total device memory.
     219              : !> \param free ...
     220              : !> \param total ...
     221              : !> \author Ole Schuett
     222              : ! **************************************************************************************************
     223            0 :    SUBROUTINE offload_mem_info(free, total)
     224              :       INTEGER(KIND=int_8), INTENT(OUT)                   :: free, total
     225              : 
     226              :       INTEGER(KIND=C_SIZE_T)                             :: my_free, my_total
     227              :       INTERFACE
     228              :          SUBROUTINE offload_mem_info_c(free, total) BIND(C, name="offload_mem_info")
     229              :             IMPORT :: C_SIZE_T
     230              :             INTEGER(KIND=C_SIZE_T)                   :: free, total
     231              :          END SUBROUTINE offload_mem_info_c
     232              :       END INTERFACE
     233              : 
     234            0 :       CALL offload_mem_info_c(my_free, my_total)
     235              : 
     236              :       ! On 32-bit architectures this converts from int_4 to int_8.
     237            0 :       free = my_free
     238            0 :       total = my_total
     239              : 
     240            0 :    END SUBROUTINE offload_mem_info
     241              : 
     242              : ! **************************************************************************************************
     243              : !> \brief Allocates a buffer of given length, ie. number of elements.
     244              : !> \param length ...
     245              : !> \param buffer ...
     246              : !> \author Ole Schuett
     247              : ! **************************************************************************************************
     248       313642 :    SUBROUTINE offload_create_buffer(length, buffer)
     249              :       INTEGER, INTENT(IN)                                :: length
     250              :       TYPE(offload_buffer_type), INTENT(INOUT)           :: buffer
     251              : 
     252              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'offload_create_buffer'
     253              : 
     254              :       INTEGER                                            :: handle
     255              :       TYPE(C_PTR)                                        :: host_buffer_c
     256              :       INTERFACE
     257              :          SUBROUTINE offload_create_buffer_c(length, buffer) &
     258              :             BIND(C, name="offload_create_buffer")
     259              :             IMPORT :: C_PTR, C_INT
     260              :             INTEGER(KIND=C_INT), VALUE                :: length
     261              :             TYPE(C_PTR)                               :: buffer
     262              :          END SUBROUTINE offload_create_buffer_c
     263              :       END INTERFACE
     264              :       INTERFACE
     265              :          FUNCTION offload_get_buffer_host_pointer_c(buffer) &
     266              :             BIND(C, name="offload_get_buffer_host_pointer")
     267              :             IMPORT :: C_PTR
     268              :             TYPE(C_PTR), VALUE                        :: buffer
     269              :             TYPE(C_PTR)                               :: offload_get_buffer_host_pointer_c
     270              :          END FUNCTION offload_get_buffer_host_pointer_c
     271              :       END INTERFACE
     272              : 
     273       313642 :       CALL timeset(routineN, handle)
     274              : 
     275       313642 :       IF (ASSOCIATED(buffer%host_buffer)) THEN
     276        12944 :          IF (SIZE(buffer%host_buffer) == 0) DEALLOCATE (buffer%host_buffer)
     277        12944 :          IF (ASSOCIATED(buffer%host_buffer)) NULLIFY (buffer%host_buffer)
     278              :       END IF
     279              : 
     280       313642 :       CALL offload_create_buffer_c(length=length, buffer=buffer%c_ptr)
     281       313642 :       CPASSERT(C_ASSOCIATED(buffer%c_ptr))
     282              : 
     283       313642 :       IF (length == 0) THEN
     284              :          ! While C_F_POINTER usually accepts a NULL pointer it's not standard compliant.
     285          490 :          ALLOCATE (buffer%host_buffer(0))
     286              :       ELSE
     287       313152 :          host_buffer_c = offload_get_buffer_host_pointer_c(buffer%c_ptr)
     288       313152 :          CPASSERT(C_ASSOCIATED(host_buffer_c))
     289       626304 :          CALL C_F_POINTER(host_buffer_c, buffer%host_buffer, shape=[length])
     290              :       END IF
     291              : 
     292       313642 :       CALL timestop(handle)
     293       313642 :    END SUBROUTINE offload_create_buffer
     294              : 
     295              : ! **************************************************************************************************
     296              : !> \brief Deallocates given buffer.
     297              : !> \param buffer ...
     298              : !> \author Ole Schuett
     299              : ! **************************************************************************************************
     300       302450 :    SUBROUTINE offload_free_buffer(buffer)
     301              :       TYPE(offload_buffer_type), INTENT(INOUT)           :: buffer
     302              : 
     303              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'offload_free_buffer'
     304              : 
     305              :       INTEGER                                            :: handle
     306              :       INTERFACE
     307              :          SUBROUTINE offload_free_buffer_c(buffer) &
     308              :             BIND(C, name="offload_free_buffer")
     309              :             IMPORT :: C_PTR
     310              :             TYPE(C_PTR), VALUE                        :: buffer
     311              :          END SUBROUTINE offload_free_buffer_c
     312              :       END INTERFACE
     313              : 
     314       302450 :       CALL timeset(routineN, handle)
     315              : 
     316       302450 :       IF (C_ASSOCIATED(buffer%c_ptr)) THEN
     317              : 
     318       300698 :          CALL offload_free_buffer_c(buffer%c_ptr)
     319              : 
     320       300698 :          buffer%c_ptr = C_NULL_PTR
     321              : 
     322       300698 :          IF (SIZE(buffer%host_buffer) == 0) THEN
     323          402 :             DEALLOCATE (buffer%host_buffer)
     324              :          ELSE
     325       300296 :             NULLIFY (buffer%host_buffer)
     326              :          END IF
     327              :       END IF
     328              : 
     329       302450 :       CALL timestop(handle)
     330       302450 :    END SUBROUTINE offload_free_buffer
     331              : 
     332              : ! **************************************************************************************************
     333              : !> \brief Print allocation statistics.
     334              : !> \param mpi_comm ...
     335              : !> \param output_unit ...
     336              : !> \author Ole Schuett
     337              : ! **************************************************************************************************
     338        10604 :    SUBROUTINE offload_mempool_stats_print(mpi_comm, output_unit)
     339              :       TYPE(mp_comm_type), INTENT(IN)                     :: mpi_comm
     340              :       INTEGER, INTENT(IN)                                :: output_unit
     341              : 
     342              :       INTERFACE
     343              :          SUBROUTINE offload_mempool_stats_print_c(mpi_comm, print_func, output_unit) &
     344              :             BIND(C, name="offload_mempool_stats_print")
     345              :             IMPORT :: C_FUNPTR, C_INT
     346              :             INTEGER(KIND=C_INT), VALUE          :: mpi_comm
     347              :             TYPE(C_FUNPTR), VALUE               :: print_func
     348              :             INTEGER(KIND=C_INT), VALUE          :: output_unit
     349              :          END SUBROUTINE offload_mempool_stats_print_c
     350              :       END INTERFACE
     351              : 
     352              :       ! Since Fortran units groups can't be used from C, we pass a function pointer instead.
     353              :       CALL offload_mempool_stats_print_c(mpi_comm=mpi_comm%get_handle(), &
     354              :                                          print_func=C_FUNLOC(print_func), &
     355        10604 :                                          output_unit=output_unit)
     356              : 
     357        10604 :    END SUBROUTINE offload_mempool_stats_print
     358              : 
     359              : ! **************************************************************************************************
     360              : !> \brief Callback to write to a Fortran output unit (called by C-side).
     361              : !> \param msg to be printed.
     362              : !> \param msglen number of characters excluding the terminating character.
     363              : !> \param output_unit used for output.
     364              : !> \author Hans Pabst
     365              : ! **************************************************************************************************
     366        83016 :    SUBROUTINE print_func(msg, msglen, output_unit) BIND(C, name="offload_api_print_func")
     367              :       CHARACTER(KIND=C_CHAR), INTENT(IN)                 :: msg(*)
     368              :       INTEGER(KIND=C_INT), INTENT(IN), VALUE             :: msglen, output_unit
     369              : 
     370        83016 :       IF (output_unit <= 0) RETURN ! Omit to print the message.
     371        41760 :       WRITE (output_unit, FMT="(100A)", ADVANCE="NO") msg(1:msglen)
     372              :    END SUBROUTINE print_func
     373            0 : END MODULE offload_api
        

Generated by: LCOV version 2.0-1