(git:db0abe2)
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-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! **************************************************************************************************
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
37
39 REAL(kind=dp), DIMENSION(:), CONTIGUOUS, POINTER :: host_buffer => null()
40 TYPE(c_ptr) :: c_ptr = c_null_ptr
41 END TYPE offload_buffer_type
42
43CONTAINS
44
45! **************************************************************************************************
46!> \brief allocate pinned memory.
47!> \param buffer address of the buffer
48!> \param length length of the buffer
49!> \return 0
50! **************************************************************************************************
51 FUNCTION offload_malloc_pinned_mem(buffer, length) RESULT(res)
52 TYPE(c_ptr) :: buffer
53 INTEGER(C_SIZE_T), VALUE :: length
54 INTEGER :: res
55
56 INTERFACE
57 FUNCTION offload_malloc_pinned_mem_c(buffer, length) &
58 BIND(C, name="offload_host_malloc")
59 IMPORT c_size_t, c_ptr, c_int
60 TYPE(c_ptr) :: buffer
61 INTEGER(C_SIZE_T), VALUE :: length
62 INTEGER(KIND=C_INT) :: offload_malloc_pinned_mem_c
63 END FUNCTION offload_malloc_pinned_mem_c
64 END INTERFACE
65
66 res = offload_malloc_pinned_mem_c(buffer, length)
67 END FUNCTION offload_malloc_pinned_mem
68
69! **************************************************************************************************
70!> \brief free pinned memory
71!> \param buffer address of the buffer
72!> \return 0
73! **************************************************************************************************
74 FUNCTION offload_free_pinned_mem(buffer) RESULT(res)
75 TYPE(c_ptr), VALUE :: buffer
76 INTEGER :: res
77
78 INTERFACE
79 FUNCTION offload_free_pinned_mem_c(buffer) &
80 BIND(C, name="offload_host_free")
81 IMPORT c_ptr, c_int
82 INTEGER(KIND=C_INT) :: offload_free_pinned_mem_c
83 TYPE(c_ptr), VALUE :: buffer
84 END FUNCTION offload_free_pinned_mem_c
85 END INTERFACE
86
87 res = offload_free_pinned_mem_c(buffer)
88 END FUNCTION offload_free_pinned_mem
89
90! **************************************************************************************************
91!> \brief Initialize runtime.
92!> \return ...
93!> \author Rocco Meli
94! **************************************************************************************************
95 SUBROUTINE offload_init()
96 INTERFACE
97 SUBROUTINE offload_init_c() &
98 BIND(C, name="offload_init")
99 END SUBROUTINE offload_init_c
100 END INTERFACE
101
102 CALL offload_init_c()
103
104 END SUBROUTINE offload_init
105
106! **************************************************************************************************
107!> \brief Returns the number of available devices.
108!> \return ...
109!> \author Ole Schuett
110! **************************************************************************************************
111 FUNCTION offload_get_device_count() RESULT(count)
112 INTEGER :: count
113
114 INTERFACE
115 FUNCTION offload_get_device_count_c() &
116 BIND(C, name="offload_get_device_count")
117 IMPORT :: c_int
118 INTEGER(KIND=C_INT) :: offload_get_device_count_c
119 END FUNCTION offload_get_device_count_c
120 END INTERFACE
121
122 count = offload_get_device_count_c()
123
124 END FUNCTION offload_get_device_count
125
126! **************************************************************************************************
127!> \brief Selects the chosen device to be used.
128!> \param device_id ...
129!> \author Ole Schuett
130! **************************************************************************************************
131 SUBROUTINE offload_set_chosen_device(device_id)
132 INTEGER, INTENT(IN) :: device_id
133
134 INTERFACE
135 SUBROUTINE offload_set_chosen_device_c(device_id) &
136 BIND(C, name="offload_set_chosen_device")
137 IMPORT :: c_int
138 INTEGER(KIND=C_INT), VALUE :: device_id
139 END SUBROUTINE offload_set_chosen_device_c
140 END INTERFACE
141
142 CALL offload_set_chosen_device_c(device_id=device_id)
143
144 END SUBROUTINE offload_set_chosen_device
145
146! **************************************************************************************************
147!> \brief Returns the chosen device.
148!> \return ...
149!> \author Ole Schuett
150! **************************************************************************************************
151 FUNCTION offload_get_chosen_device() RESULT(device_id)
152 INTEGER :: device_id
153
154 INTERFACE
155 FUNCTION offload_get_chosen_device_c() &
156 BIND(C, name="offload_get_chosen_device")
157 IMPORT :: c_int
158 INTEGER(KIND=C_INT) :: offload_get_chosen_device_c
159 END FUNCTION offload_get_chosen_device_c
160 END INTERFACE
161
162 device_id = offload_get_chosen_device_c()
163
164 IF (device_id < 0) THEN
165 cpabort("No offload device has been chosen.")
166 END IF
167
168 END FUNCTION offload_get_chosen_device
169
170! **************************************************************************************************
171!> \brief Activates the device selected via offload_set_chosen_device()
172!> \author Ole Schuett
173! **************************************************************************************************
175
176 INTERFACE
177 SUBROUTINE offload_activate_chosen_device_c() &
178 BIND(C, name="offload_activate_chosen_device")
179 END SUBROUTINE offload_activate_chosen_device_c
180 END INTERFACE
181
182 CALL offload_activate_chosen_device_c()
183
184 END SUBROUTINE offload_activate_chosen_device
185
186! **************************************************************************************************
187!> \brief Starts a timing range.
188!> \param routineN ...
189!> \author Ole Schuett
190! **************************************************************************************************
191 SUBROUTINE offload_timeset(routineN)
192 CHARACTER(LEN=*), INTENT(IN) :: routinen
193
194 INTERFACE
195 SUBROUTINE offload_timeset_c(message) BIND(C, name="offload_timeset")
196 IMPORT :: c_char
197 CHARACTER(kind=C_CHAR), DIMENSION(*), INTENT(IN) :: message
198 END SUBROUTINE offload_timeset_c
199 END INTERFACE
200
201 CALL offload_timeset_c(trim(routinen)//c_null_char)
202
203 END SUBROUTINE offload_timeset
204
205! **************************************************************************************************
206!> \brief Ends a timing range.
207!> \author Ole Schuett
208! **************************************************************************************************
209 SUBROUTINE offload_timestop()
210
211 INTERFACE
212 SUBROUTINE offload_timestop_c() BIND(C, name="offload_timestop")
213 END SUBROUTINE offload_timestop_c
214 END INTERFACE
215
216 CALL offload_timestop_c()
217
218 END SUBROUTINE offload_timestop
219
220! **************************************************************************************************
221!> \brief Gets free and total device memory.
222!> \param free ...
223!> \param total ...
224!> \author Ole Schuett
225! **************************************************************************************************
226 SUBROUTINE offload_mem_info(free, total)
227 INTEGER(KIND=int_8), INTENT(OUT) :: free, total
228
229 INTEGER(KIND=C_SIZE_T) :: my_free, my_total
230 INTERFACE
231 SUBROUTINE offload_mem_info_c(free, total) BIND(C, name="offload_mem_info")
232 IMPORT :: c_size_t
233 INTEGER(KIND=C_SIZE_T) :: free, total
234 END SUBROUTINE offload_mem_info_c
235 END INTERFACE
236
237 CALL offload_mem_info_c(my_free, my_total)
238
239 ! On 32-bit architectures this converts from int_4 to int_8.
240 free = my_free
241 total = my_total
242
243 END SUBROUTINE offload_mem_info
244
245! **************************************************************************************************
246!> \brief Allocates a buffer of given length, ie. number of elements.
247!> \param length ...
248!> \param buffer ...
249!> \author Ole Schuett
250! **************************************************************************************************
251 SUBROUTINE offload_create_buffer(length, buffer)
252 INTEGER, INTENT(IN) :: length
253 TYPE(offload_buffer_type), INTENT(INOUT) :: buffer
254
255 CHARACTER(LEN=*), PARAMETER :: routinen = 'offload_create_buffer'
256
257 INTEGER :: handle
258 TYPE(c_ptr) :: host_buffer_c
259 INTERFACE
260 SUBROUTINE offload_create_buffer_c(length, buffer) &
261 BIND(C, name="offload_create_buffer")
262 IMPORT :: c_ptr, c_int
263 INTEGER(KIND=C_INT), VALUE :: length
264 TYPE(c_ptr) :: buffer
265 END SUBROUTINE offload_create_buffer_c
266 END INTERFACE
267 INTERFACE
268 FUNCTION offload_get_buffer_host_pointer_c(buffer) &
269 BIND(C, name="offload_get_buffer_host_pointer")
270 IMPORT :: c_ptr
271 TYPE(c_ptr), VALUE :: buffer
272 TYPE(c_ptr) :: offload_get_buffer_host_pointer_c
273 END FUNCTION offload_get_buffer_host_pointer_c
274 END INTERFACE
275
276 CALL timeset(routinen, handle)
277
278 IF (ASSOCIATED(buffer%host_buffer)) THEN
279 IF (SIZE(buffer%host_buffer) == 0) DEALLOCATE (buffer%host_buffer)
280 IF (ASSOCIATED(buffer%host_buffer)) NULLIFY (buffer%host_buffer)
281 END IF
282
283 CALL offload_create_buffer_c(length=length, buffer=buffer%c_ptr)
284 cpassert(c_associated(buffer%c_ptr))
285
286 IF (length == 0) THEN
287 ! While C_F_POINTER usually accepts a NULL pointer it's not standard compliant.
288 ALLOCATE (buffer%host_buffer(0))
289 ELSE
290 host_buffer_c = offload_get_buffer_host_pointer_c(buffer%c_ptr)
291 cpassert(c_associated(host_buffer_c))
292 CALL c_f_pointer(host_buffer_c, buffer%host_buffer, shape=[length])
293 END IF
294
295 CALL timestop(handle)
296 END SUBROUTINE offload_create_buffer
297
298! **************************************************************************************************
299!> \brief Deallocates given buffer.
300!> \param buffer ...
301!> \author Ole Schuett
302! **************************************************************************************************
303 SUBROUTINE offload_free_buffer(buffer)
304 TYPE(offload_buffer_type), INTENT(INOUT) :: buffer
305
306 CHARACTER(LEN=*), PARAMETER :: routinen = 'offload_free_buffer'
307
308 INTEGER :: handle
309 INTERFACE
310 SUBROUTINE offload_free_buffer_c(buffer) &
311 BIND(C, name="offload_free_buffer")
312 IMPORT :: c_ptr
313 TYPE(c_ptr), VALUE :: buffer
314 END SUBROUTINE offload_free_buffer_c
315 END INTERFACE
316
317 CALL timeset(routinen, handle)
318
319 IF (c_associated(buffer%c_ptr)) THEN
320
321 CALL offload_free_buffer_c(buffer%c_ptr)
322
323 buffer%c_ptr = c_null_ptr
324
325 IF (ASSOCIATED(buffer%host_buffer)) THEN
326 IF (SIZE(buffer%host_buffer) == 0) THEN
327 DEALLOCATE (buffer%host_buffer)
328 ELSE
329 NULLIFY (buffer%host_buffer)
330 END IF
331 END IF
332 END IF
333
334 CALL timestop(handle)
335 END SUBROUTINE offload_free_buffer
336
337! **************************************************************************************************
338!> \brief Print allocation statistics.
339!> \param mpi_comm ...
340!> \param output_unit ...
341!> \author Ole Schuett
342! **************************************************************************************************
343 SUBROUTINE offload_mempool_stats_print(mpi_comm, output_unit)
344 TYPE(mp_comm_type), INTENT(IN) :: mpi_comm
345 INTEGER, INTENT(IN) :: output_unit
346
347 INTERFACE
348 SUBROUTINE offload_mempool_stats_print_c(mpi_comm, print_func, output_unit) &
349 BIND(C, name="offload_mempool_stats_print")
350 IMPORT :: c_funptr, c_int
351 INTEGER(KIND=C_INT), VALUE :: mpi_comm
352 TYPE(c_funptr), VALUE :: print_func
353 INTEGER(KIND=C_INT), VALUE :: output_unit
354 END SUBROUTINE offload_mempool_stats_print_c
355 END INTERFACE
356
357 ! Since Fortran units groups can't be used from C, we pass a function pointer instead.
358 CALL offload_mempool_stats_print_c(mpi_comm=mpi_comm%get_handle(), &
359 print_func=c_funloc(print_func), &
360 output_unit=output_unit)
361
362 END SUBROUTINE offload_mempool_stats_print
363
364! **************************************************************************************************
365!> \brief Callback to write to a Fortran output unit (called by C-side).
366!> \param msg to be printed.
367!> \param msglen number of characters excluding the terminating character.
368!> \param output_unit used for output.
369!> \author Hans Pabst
370! **************************************************************************************************
371 SUBROUTINE print_func(msg, msglen, output_unit) BIND(C, name="offload_api_print_func")
372 CHARACTER(KIND=C_CHAR), INTENT(IN) :: msg(*)
373 INTEGER(KIND=C_INT), INTENT(IN), VALUE :: msglen, output_unit
374
375 IF (output_unit <= 0) RETURN ! Omit to print the message.
376 WRITE (output_unit, fmt="(100A)", advance="NO") msg(1:msglen)
377 END SUBROUTINE print_func
378
379 ! GPU data transfer functions
380! **************************************************************************************************
381!> \brief Copy host data to device.
382!> \param buffer ...
383!> \param length ...
384! **************************************************************************************************
385 SUBROUTINE offload_buffer_h2d(buffer, length)
386 TYPE(offload_buffer_type), INTENT(INOUT) :: buffer
387 INTEGER, INTENT(IN) :: length
388
389 INTERFACE
390 SUBROUTINE offload_buffer_h2d_c(buffer, length) &
391 BIND(C, name="offload_buffer_h2d")
392 IMPORT :: c_ptr, c_int
393 TYPE(c_ptr), VALUE :: buffer
394 INTEGER(KIND=C_INT), VALUE :: length
395 END SUBROUTINE offload_buffer_h2d_c
396 END INTERFACE
397
398 CALL offload_buffer_h2d_c(buffer%c_ptr, length)
399 END SUBROUTINE offload_buffer_h2d
400
401! **************************************************************************************************
402!> \brief Copy device data to host.
403!> \param buffer ...
404!> \param length ...
405! **************************************************************************************************
406 SUBROUTINE offload_buffer_d2h(buffer, length)
407 TYPE(offload_buffer_type), INTENT(INOUT) :: buffer
408 INTEGER, INTENT(IN) :: length
409
410 INTERFACE
411 SUBROUTINE offload_buffer_d2h_c(buffer, length) &
412 BIND(C, name="offload_buffer_d2h")
413 IMPORT :: c_ptr, c_int
414 TYPE(c_ptr), VALUE :: buffer
415 INTEGER(KIND=C_INT), VALUE :: length
416 END SUBROUTINE offload_buffer_d2h_c
417 END INTERFACE
418
419 CALL offload_buffer_d2h_c(buffer%c_ptr, length)
420 END SUBROUTINE offload_buffer_d2h
421
422! **************************************************************************************************
423!> \brief Return a C pointer to the buffer's underlying device memory.
424!> \param buffer ...
425!> \return ...
426!> \author Samal Bibek
427! **************************************************************************************************
428 FUNCTION offload_get_buffer_device_pointer(buffer) RESULT(device_ptr)
429 TYPE(offload_buffer_type), INTENT(IN) :: buffer
430 TYPE(c_ptr) :: device_ptr
431
432 INTERFACE
433 FUNCTION offload_get_buffer_device_pointer_c(buffer) &
434 BIND(C, name="offload_get_buffer_device_pointer")
435 IMPORT :: c_ptr
436 TYPE(c_ptr), VALUE :: buffer
437 TYPE(c_ptr) :: offload_get_buffer_device_pointer_c
438 END FUNCTION offload_get_buffer_device_pointer_c
439 END INTERFACE
440
441 device_ptr = offload_get_buffer_device_pointer_c(buffer%c_ptr)
443
444! **************************************************************************************************
445!> \brief Blocks until all outstanding device work has completed.
446!> \author Samal Bibek
447! **************************************************************************************************
449 INTERFACE
450 SUBROUTINE offload_device_synchronize_c() &
451 BIND(C, name="offload_device_synchronize")
452 END SUBROUTINE offload_device_synchronize_c
453 END INTERFACE
454
455 CALL offload_device_synchronize_c()
456 END SUBROUTINE offload_device_synchronize
457! **************************************************************************************************
458!> \brief Return a C pointer to the buffer's host memory.
459!> \param buffer ...
460!> \return ...
461! **************************************************************************************************
462 FUNCTION offload_get_buffer_host_pointer(buffer) RESULT(host_ptr)
463 TYPE(offload_buffer_type), INTENT(IN) :: buffer
464 TYPE(c_ptr) :: host_ptr
465
466 INTERFACE
467 FUNCTION offload_get_buffer_host_pointer_c(buffer) &
468 BIND(C, name="offload_get_buffer_host_pointer")
469 IMPORT :: c_ptr
470 TYPE(c_ptr), VALUE :: buffer
471 TYPE(c_ptr) :: offload_get_buffer_host_pointer_c
472 END FUNCTION offload_get_buffer_host_pointer_c
473 END INTERFACE
474
475 host_ptr = offload_get_buffer_host_pointer_c(buffer%c_ptr)
477END MODULE offload_api
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_buffer_h2d(buffer, length)
Copy host data to device.
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().
type(c_ptr) function, public offload_get_buffer_device_pointer(buffer)
Return a C pointer to the buffer's underlying device memory.
type(c_ptr) function, public offload_get_buffer_host_pointer(buffer)
Return a C pointer to the buffer's host memory.
subroutine, public offload_timestop()
Ends a timing range.
integer function, public offload_free_pinned_mem(buffer)
free pinned memory
Definition offload_api.F:75
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:52
subroutine, public offload_device_synchronize()
Blocks until all outstanding device work has completed.
subroutine, public offload_init()
Initialize runtime.
Definition offload_api.F:96
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.
subroutine, public offload_buffer_d2h(buffer, length)
Copy device data to host.
integer function, public offload_get_chosen_device()
Returns the chosen device.