(git:da6e80d)
Loading...
Searching...
No Matches
offload_api.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2025 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! **************************************************************************************************
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
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
34
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
40CONTAINS
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 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 res = offload_malloc_pinned_mem_c(buffer, length)
64 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 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 res = offload_free_pinned_mem_c(buffer)
85 END FUNCTION offload_free_pinned_mem
86
87! **************************************************************************************************
88!> \brief Initialize runtime.
89!> \return ...
90!> \author Rocco Meli
91! **************************************************************************************************
92 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 CALL offload_init_c()
100
101 END SUBROUTINE offload_init
102
103! **************************************************************************************************
104!> \brief Returns the number of available devices.
105!> \return ...
106!> \author Ole Schuett
107! **************************************************************************************************
108 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 count = offload_get_device_count_c()
120
121 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 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 CALL offload_set_chosen_device_c(device_id=device_id)
140
141 END SUBROUTINE offload_set_chosen_device
142
143! **************************************************************************************************
144!> \brief Returns the chosen device.
145!> \return ...
146!> \author Ole Schuett
147! **************************************************************************************************
148 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 device_id = offload_get_chosen_device_c()
160
161 IF (device_id < 0) &
162 cpabort("No offload device has been chosen.")
163
164 END FUNCTION offload_get_chosen_device
165
166! **************************************************************************************************
167!> \brief Activates the device selected via offload_set_chosen_device()
168!> \author Ole Schuett
169! **************************************************************************************************
171
172 INTERFACE
173 SUBROUTINE offload_activate_chosen_device_c() &
174 BIND(C, name="offload_activate_chosen_device")
175 END SUBROUTINE offload_activate_chosen_device_c
176 END INTERFACE
177
178 CALL offload_activate_chosen_device_c()
179
180 END SUBROUTINE offload_activate_chosen_device
181
182! **************************************************************************************************
183!> \brief Starts a timing range.
184!> \param routineN ...
185!> \author Ole Schuett
186! **************************************************************************************************
187 SUBROUTINE offload_timeset(routineN)
188 CHARACTER(LEN=*), INTENT(IN) :: routinen
189
190 INTERFACE
191 SUBROUTINE offload_timeset_c(message) BIND(C, name="offload_timeset")
192 IMPORT :: c_char
193 CHARACTER(kind=C_CHAR), DIMENSION(*), INTENT(IN) :: message
194 END SUBROUTINE offload_timeset_c
195 END INTERFACE
196
197 CALL offload_timeset_c(trim(routinen)//c_null_char)
198
199 END SUBROUTINE offload_timeset
200
201! **************************************************************************************************
202!> \brief Ends a timing range.
203!> \author Ole Schuett
204! **************************************************************************************************
205 SUBROUTINE offload_timestop()
206
207 INTERFACE
208 SUBROUTINE offload_timestop_c() BIND(C, name="offload_timestop")
209 END SUBROUTINE offload_timestop_c
210 END INTERFACE
211
212 CALL offload_timestop_c()
213
214 END SUBROUTINE offload_timestop
215
216! **************************************************************************************************
217!> \brief Gets free and total device memory.
218!> \param free ...
219!> \param total ...
220!> \author Ole Schuett
221! **************************************************************************************************
222 SUBROUTINE offload_mem_info(free, total)
223 INTEGER(KIND=int_8), INTENT(OUT) :: free, total
224
225 INTEGER(KIND=C_SIZE_T) :: my_free, my_total
226 INTERFACE
227 SUBROUTINE offload_mem_info_c(free, total) BIND(C, name="offload_mem_info")
228 IMPORT :: c_size_t
229 INTEGER(KIND=C_SIZE_T) :: free, total
230 END SUBROUTINE offload_mem_info_c
231 END INTERFACE
232
233 CALL offload_mem_info_c(my_free, my_total)
234
235 ! On 32-bit architectures this converts from int_4 to int_8.
236 free = my_free
237 total = my_total
238
239 END SUBROUTINE offload_mem_info
240
241! **************************************************************************************************
242!> \brief Allocates a buffer of given length, ie. number of elements.
243!> \param length ...
244!> \param buffer ...
245!> \author Ole Schuett
246! **************************************************************************************************
247 SUBROUTINE offload_create_buffer(length, buffer)
248 INTEGER, INTENT(IN) :: length
249 TYPE(offload_buffer_type), INTENT(INOUT) :: buffer
250
251 CHARACTER(LEN=*), PARAMETER :: routinen = 'offload_create_buffer'
252
253 INTEGER :: handle
254 TYPE(c_ptr) :: host_buffer_c
255 INTERFACE
256 SUBROUTINE offload_create_buffer_c(length, buffer) &
257 BIND(C, name="offload_create_buffer")
258 IMPORT :: c_ptr, c_int
259 INTEGER(KIND=C_INT), VALUE :: length
260 TYPE(c_ptr) :: buffer
261 END SUBROUTINE offload_create_buffer_c
262 END INTERFACE
263 INTERFACE
264
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 CALL timeset(routinen, handle)
274
275 IF (ASSOCIATED(buffer%host_buffer)) THEN
276 IF (SIZE(buffer%host_buffer) == 0) DEALLOCATE (buffer%host_buffer)
277 END IF
278
279 CALL offload_create_buffer_c(length=length, buffer=buffer%c_ptr)
280 cpassert(c_associated(buffer%c_ptr))
281
282 IF (length == 0) THEN
283 ! While C_F_POINTER usually accepts a NULL pointer it's not standard compliant.
284 ALLOCATE (buffer%host_buffer(0))
285 ELSE
286 host_buffer_c = offload_get_buffer_host_pointer_c(buffer%c_ptr)
287 cpassert(c_associated(host_buffer_c))
288 CALL c_f_pointer(host_buffer_c, buffer%host_buffer, shape=(/length/))
289 END IF
290
291 CALL timestop(handle)
292 END SUBROUTINE offload_create_buffer
293
294! **************************************************************************************************
295!> \brief Deallocates given buffer.
296!> \param buffer ...
297!> \author Ole Schuett
298! **************************************************************************************************
299 SUBROUTINE offload_free_buffer(buffer)
300 TYPE(offload_buffer_type), INTENT(INOUT) :: buffer
301
302 CHARACTER(LEN=*), PARAMETER :: routinen = 'offload_free_buffer'
303
304 INTEGER :: handle
305 INTERFACE
306 SUBROUTINE offload_free_buffer_c(buffer) &
307 BIND(C, name="offload_free_buffer")
308 IMPORT :: c_ptr
309 TYPE(c_ptr), VALUE :: buffer
310 END SUBROUTINE offload_free_buffer_c
311 END INTERFACE
312
313 CALL timeset(routinen, handle)
314
315 IF (c_associated(buffer%c_ptr)) THEN
316
317 CALL offload_free_buffer_c(buffer%c_ptr)
318
319 buffer%c_ptr = c_null_ptr
320
321 IF (SIZE(buffer%host_buffer) == 0) THEN
322 DEALLOCATE (buffer%host_buffer)
323 ELSE
324 NULLIFY (buffer%host_buffer)
325 END IF
326 END IF
327
328 CALL timestop(handle)
329 END SUBROUTINE offload_free_buffer
330
331! **************************************************************************************************
332!> \brief Print allocation statistics.
333!> \param mpi_comm ...
334!> \param output_unit ...
335!> \author Ole Schuett
336! **************************************************************************************************
337 SUBROUTINE offload_mempool_stats_print(mpi_comm, output_unit)
338 TYPE(mp_comm_type), INTENT(IN) :: mpi_comm
339 INTEGER, INTENT(IN) :: output_unit
340
341 INTERFACE
342 SUBROUTINE offload_mempool_stats_print_c(mpi_comm, print_func, output_unit) &
343 BIND(C, name="offload_mempool_stats_print")
344 IMPORT :: c_funptr, c_int
345 INTEGER(KIND=C_INT), VALUE :: mpi_comm
346 TYPE(c_funptr), VALUE :: print_func
347 INTEGER(KIND=C_INT), VALUE :: output_unit
348 END SUBROUTINE offload_mempool_stats_print_c
349 END INTERFACE
350
351 ! Since Fortran units groups can't be used from C, we pass a function pointer instead.
352 CALL offload_mempool_stats_print_c(mpi_comm=mpi_comm%get_handle(), &
353 print_func=c_funloc(print_func), &
354 output_unit=output_unit)
355
356 END SUBROUTINE offload_mempool_stats_print
357
358! **************************************************************************************************
359!> \brief Callback to write to a Fortran output unit (called by C-side).
360!> \param msg to be printed.
361!> \param msglen number of characters excluding the terminating character.
362!> \param output_unit used for output.
363!> \author Hans Pabst
364! **************************************************************************************************
365 SUBROUTINE print_func(msg, msglen, output_unit) BIND(C, name="offload_api_print_func")
366 CHARACTER(KIND=C_CHAR), INTENT(IN) :: msg(*)
367 INTEGER(KIND=C_INT), INTENT(IN), VALUE :: msglen, output_unit
368
369 IF (output_unit <= 0) RETURN ! Omit to print the message.
370 WRITE (output_unit, fmt="(100A)", advance="NO") msg(1:msglen)
371 END SUBROUTINE print_func
372END MODULE offload_api
static void print_func(const char *msg, int msglen, int output_unit)
Wrapper for printf, passed to dbm_library_print_stats.
Definition dbm_miniapp.c:29
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public int_8
Definition kinds.F:54
integer, parameter, public dp
Definition kinds.F:34
Interface to the message passing library MPI.
Fortran API for the offload package, which is written in C.
Definition offload_api.F:12
subroutine, public offload_set_chosen_device(device_id)
Selects the chosen device to be used.
subroutine, public offload_free_buffer(buffer)
Deallocates given buffer.
subroutine, public offload_activate_chosen_device()
Activates the device selected via offload_set_chosen_device()
subroutine, public offload_timestop()
Ends a timing range.
integer function, public offload_free_pinned_mem(buffer)
free pinned memory
Definition offload_api.F:72
subroutine, public offload_timeset(routinen)
Starts a timing range.
integer function, public offload_get_device_count()
Returns the number of available devices.
subroutine, public offload_create_buffer(length, buffer)
Allocates a buffer of given length, ie. number of elements.
integer function, public offload_malloc_pinned_mem(buffer, length)
allocate pinned memory.
Definition offload_api.F:49
subroutine, public offload_init()
Initialize runtime.
Definition offload_api.F:93
subroutine, public offload_mem_info(free, total)
Gets free and total device memory.
subroutine, public offload_mempool_stats_print(mpi_comm, output_unit)
Print allocation statistics.
integer function, public offload_get_chosen_device()
Returns the chosen device.