Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
opencl_intf.F90
Go to the documentation of this file.
1! Copyright (c) 2021-2025, 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!
35 use num_types, only : i8
36 use utils, only : neko_error
37 use, intrinsic :: iso_c_binding
38 implicit none
39
40#ifdef HAVE_OPENCL
41
43 type(c_ptr), bind(c) :: glb_ctx = c_null_ptr
44
46 type(c_ptr), bind(c), target :: glb_device_id = c_null_ptr
47
49 enum, bind(c)
50 enumerator :: cl_success = 0
51 enumerator :: cl_device_not_found = -1
52 enumerator :: cl_device_not_available = -2
53 enumerator :: cl_compiler_not_available = -3
55 enumerator :: cl_out_of_resources = -5
56 enumerator :: cl_out_of_host_memory = -6
58 enumerator :: cl_mem_copy_overlap = -8
59 enumerator :: cl_image_format_mismatch = -9
61 enumerator :: cl_build_program_failure = -11
62 enumerator :: cl_map_failure = -12
63 end enum
64
66 enum, bind(c)
67 enumerator :: cl_mem_read_write = 1
68 enumerator :: cl_mem_write_only = 2
69 enumerator :: cl_mem_read_only = 4
70 enumerator :: cl_mem_use_host_ptr = 8
71 enumerator :: cl_mem_alloc_host_ptr = 16
72 enumerator :: cl_mem_host_write_only = 128
73 enumerator :: cl_mem_host_read_only = 256
74 enumerator :: cl_mem_host_no_access = 512
75 end enum
76
78 enum, bind(c)
79 enumerator :: cl_complete = 0
80 enumerator :: cl_running = 1
81 enumerator :: cl_submitted = 2
82 enumerator :: cl_queued = 3
83 end enum
84
86 enum, bind(c)
87 enumerator :: cl_false = 0
88 enumerator :: cl_true = 1
89 end enum
90
91 enum, bind(c)
92 enumerator :: cl_context_platform = int(z'1084')
93 end enum
94
96 enum, bind(c)
97 enumerator :: cl_device_max_compute_units = int(z'1002')
98 enumerator :: cl_device_global_mem_size = int(z'101F')
99 enumerator :: cl_device_name = 4139
100 end enum
101
103 integer(c_int64_t), parameter :: cl_device_type_default = 1
104 integer(c_int64_t), parameter :: cl_device_type_cpu = 2
105 integer(c_int64_t), parameter :: cl_device_type_gpu = 4
106 integer(c_int64_t), parameter :: cl_device_type_accelerator = 8
107 integer(c_int64_t), parameter :: cl_device_type_custom = 16
108 integer(c_int64_t), parameter :: cl_device_type_all = int(z'FFFFFFFF', i8)
109
111 integer(c_int64_t), parameter :: cl_queue_out_of_order_exec_mode_enable = 1
112 integer(c_int64_t), parameter :: cl_queue_profiling_enable = 2
113
114 interface
115 integer(c_int) function clgetplatformids(num_entries, platforms, &
116 num_platforms) bind(c, name = 'clGetPlatformIDs')
117 use, intrinsic :: iso_c_binding
118 implicit none
119 integer(c_int), value :: num_entries
120 type(c_ptr), value :: platforms
121 integer(c_int) :: num_platforms
122 end function clgetplatformids
123
124 integer(c_int) function clgetdeviceids(platform, device_type, &
125 num_entries, devices, num_devices) bind(c, name = 'clGetDeviceIDs')
126 use, intrinsic :: iso_c_binding
127 implicit none
128 type(c_ptr), value :: platform
129 integer(c_int64_t), value :: device_type
130 integer(c_int), value :: num_entries
131 type(c_ptr), value :: devices
132 integer(c_int) :: num_devices
133 end function clgetdeviceids
134
135 type (c_ptr) function clcreatecontext(properties, num_devices, devices, &
136 pfn_notify, user_data, ierr) bind(c, name = 'clCreateContext')
137 use, intrinsic :: iso_c_binding
138 implicit none
139 type(c_ptr), value :: properties
140 integer(c_int), value :: num_devices
141 type(c_ptr), value :: devices
142 type(c_funptr), value :: pfn_notify
143 type(c_ptr), value :: user_data
144 integer(c_int) :: ierr
145 end function clcreatecontext
146
147 type(c_ptr) function clcreatecommandqueue(context, device, &
148 properties, ierr) bind(c, name = 'clCreateCommandQueue')
149 use, intrinsic :: iso_c_binding
150 implicit none
151 type(c_ptr), value :: context
152 type(c_ptr), value :: device
153 integer(c_int64_t), value :: properties
154 integer(c_int) :: ierr
155 end function clcreatecommandqueue
156
157 type(c_ptr) function clcreatebuffer(context, flags, size, host_ptr, ierr) &
158 bind(c, name = 'clCreateBuffer')
159 use, intrinsic :: iso_c_binding
160 implicit none
161 type(c_ptr), value :: context
162 integer(c_int), value :: flags
163 integer(c_size_t), value :: size
164 type(c_ptr), value :: host_ptr
165 integer(c_int) :: ierr
166 end function clcreatebuffer
167
168 type(c_ptr) function clcreateuserevent(context, ierr) &
169 bind(c, name = 'clCreateUserEvent')
170 use, intrinsic :: iso_c_binding
171 implicit none
172 type(c_ptr), value :: context
173 integer(c_int) :: ierr
174 end function clcreateuserevent
175
176 integer(c_int) function clenqueuereadbuffer(queue, buffer, blocking_read, &
177 offset, size, ptr, num_events_in_wait_list, event_wait_list, event) &
178 bind(c, name = 'clEnqueueReadBuffer')
179 use, intrinsic :: iso_c_binding
180 implicit none
181 type(c_ptr), value :: queue
182 type(c_ptr), value :: buffer
183 integer(c_int), value :: blocking_read
184 integer(c_size_t), value :: offset
185 integer(c_size_t), value :: size
186 type(c_ptr), value :: ptr
187 integer(c_int), value :: num_events_in_wait_list
188 type(c_ptr), value :: event_wait_list
189 type(c_ptr), value :: event
190 end function clenqueuereadbuffer
191
192 integer(c_int) function clenqueuewritebuffer(queue, buffer, &
193 blocking_write, offset, size, ptr, num_events_in_wait_list, &
194 event_wait_list, event) bind(c, name = 'clEnqueueWriteBuffer')
195 use, intrinsic :: iso_c_binding
196 implicit none
197 type(c_ptr), value :: queue
198 type(c_ptr), value :: buffer
199 integer(c_int), value :: blocking_write
200 integer(c_size_t), value :: offset
201 integer(c_size_t), value :: size
202 type(c_ptr), value :: ptr
203 integer(c_int), value :: num_events_in_wait_list
204 type(c_ptr), value :: event_wait_list
205 type(c_ptr), value :: event
206 end function clenqueuewritebuffer
207
208 integer(c_int) function clenqueuecopybuffer(queue, src_buffer, &
209 dst_buffer, src_offset, dst_offset, size, num_events_in_wait_list, &
210 event_wait_list, event) bind(c, name = 'clEnqueueCopyBuffer')
211 use, intrinsic :: iso_c_binding
212 implicit none
213 type(c_ptr), value :: queue
214 type(c_ptr), value :: src_buffer
215 type(c_ptr), value :: dst_buffer
216 integer(c_size_t), value :: src_offset
217 integer(c_size_t), value :: dst_offset
218 integer(c_size_t), value :: size
219 integer(c_int), value :: num_events_in_wait_list
220 type(c_ptr), value :: event_wait_list
221 type(c_ptr), value :: event
222 end function clenqueuecopybuffer
223
224 integer(c_int) function clenqueuefillbuffer(queue, buffer, &
225 pattern, pattern_size, offset, size, num_events_in_wait_list, &
226 event_wait_list, event) bind(c, name = 'clEnqueueFillBuffer')
227 use, intrinsic :: iso_c_binding
228 implicit none
229 type(c_ptr), value :: queue
230 type(c_ptr), value :: buffer
231 type(c_ptr), value :: pattern
232 integer(c_size_t), value :: pattern_size
233 integer(c_size_t), value :: offset
234 integer(c_size_t), value :: size
235 integer(c_int), value :: num_events_in_wait_list
236 type(c_ptr), value :: event_wait_list
237 type(c_ptr), value :: event
238 end function clenqueuefillbuffer
239
240 integer(c_int) function clenqueuemarkerwithwaitlist &
241 (queue, num_events_in_wait_list, event_wait_list, event) &
242 bind(c, name = 'clEnqueueMarkerWithWaitList')
243 use, intrinsic :: iso_c_binding
244 implicit none
245 type(c_ptr), value :: queue
246 integer(c_int), value :: num_events_in_wait_list
247 type(c_ptr), value :: event_wait_list
248 type(c_ptr), value :: event
249 end function clenqueuemarkerwithwaitlist
250
251 integer(c_int) function clenqueuemarker(cmd_queue, event) &
252 bind(c, name = 'clEnqueueMarker')
253 use, intrinsic :: iso_c_binding
254 implicit none
255 type(c_ptr), value :: cmd_queue
256 type(c_ptr), value :: event
257 end function clenqueuemarker
258
259 integer(c_int) function clenqueuebarrier(cmd_queue) &
260 bind(c, name = 'clEnqueueBarrier')
261 use, intrinsic :: iso_c_binding
262 implicit none
263 type(c_ptr), value :: cmd_queue
264 end function clenqueuebarrier
265
266 integer(c_int) function clenqueuewaitforevents(queue, &
267 num_events, event_list) bind(c, name = 'clEnqueueWaitForEvents')
268 use, intrinsic :: iso_c_binding
269 implicit none
270 type(c_ptr), value :: queue
271 integer(c_int), value :: num_events
272 type(c_ptr), value :: event_list
273 end function clenqueuewaitforevents
274
275 integer(c_int) function clwaitforevents(num_events, event_list) &
276 bind(c, name = 'clWaitForEvents')
277 use, intrinsic :: iso_c_binding
278 implicit none
279 integer(c_int), value :: num_events
280 type(c_ptr), value :: event_list
281 end function clwaitforevents
282
283 integer(c_int) function clsetusereventstatus(event, status) &
284 bind(c, name = 'clSetUserEventStatus')
285 use, intrinsic :: iso_c_binding
286 implicit none
287 type(c_ptr), value :: event
288 integer(c_int), value :: status
289 end function clsetusereventstatus
290
291 integer(c_int) function clgetdeviceinfo(device, param_name, &
292 param_value_size, param_value, param_value_size_ret) &
293 bind(c, name = 'clGetDeviceInfo')
294 use, intrinsic :: iso_c_binding
295 implicit none
296 type(c_ptr), value :: device
297 integer(c_int), value :: param_name
298 integer(c_size_t), value :: param_value_size
299 type(c_ptr), value :: param_value
300 type(c_ptr), value :: param_value_size_ret
301 end function clgetdeviceinfo
302
303 integer(c_int) function clreleasecontext(context) &
304 bind(c, name = 'clReleaseContext')
305 use, intrinsic :: iso_c_binding
306 implicit none
307 type(c_ptr), value :: context
308 end function clreleasecontext
309
310 integer(c_int) function clreleasecommandqueue(queue) &
311 bind(c, name = 'clReleaseCommandQueue')
312 use, intrinsic :: iso_c_binding
313 implicit none
314 type(c_ptr), value :: queue
315 end function clreleasecommandqueue
316
317 integer(c_int) function clreleasedevice(device) &
318 bind(c, name = 'clReleaseDevice')
319 use, intrinsic :: iso_c_binding
320 implicit none
321 type(c_ptr), value :: device
322 end function clreleasedevice
323
324 integer(c_int) function clreleaseprogram(prgm) &
325 bind(c, name = 'clReleaseProgram')
326 use, intrinsic :: iso_c_binding
327 implicit none
328 type(c_ptr), value :: prgm
329 end function clreleaseprogram
330
331 integer(c_int) function clreleasememobject(ptr_d) &
332 bind(c, name = 'clReleaseMemObject')
333 use, intrinsic :: iso_c_binding
334 implicit none
335 type(c_ptr), value :: ptr_d
336 end function clreleasememobject
337
338 integer(c_int) function clreleaseevent(event) &
339 bind(c, name = 'clReleaseEvent')
340 use, intrinsic :: iso_c_binding
341 implicit none
342 type(c_ptr), value :: event
343 end function clreleaseevent
344
345 integer(c_int) function clflush(cmd_queue) &
346 bind(c, name = 'clFlush')
347 use, intrinsic :: iso_c_binding
348 implicit none
349 type(c_ptr), value :: cmd_queue
350 end function clflush
351
352 integer(c_int) function clfinish(cmd_queue) &
353 bind(c, name = 'clFinish')
354 use, intrinsic :: iso_c_binding
355 implicit none
356 type(c_ptr), value :: cmd_queue
357 end function clfinish
358
360 bind(c, name = 'opencl_buffer_free_all')
361 end subroutine opencl_buffer_free_all
362 end interface
363
364contains
365
366 subroutine opencl_init(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
367 type(c_ptr), intent(inout) :: glb_cmd_queue
368 type(c_ptr), intent(inout) :: aux_cmd_queue
369 type(c_ptr), intent(inout) :: prf_cmd_queue
370 type(c_ptr), target :: platform_id
371 integer(c_int) :: num_platforms, num_devices, ierr
372 integer(c_intptr_t) :: ctx_prop(3)
373 integer(c_int64_t), parameter :: queue_props = 0
374 integer :: i
375
376 if (clgetplatformids(1, c_loc(platform_id), &
377 num_platforms) .ne. cl_success) then
378 call neko_error('Failed to get a platform id')
379 end if
380
381 if (clgetdeviceids(platform_id, cl_device_type_gpu, 1, &
382 c_loc(glb_device_id), num_devices) .ne. cl_success) then
383 call neko_error('Failed to get a device id')
384 end if
385
386 if (c_associated(glb_ctx)) then
387 ! Release all device buffers created against the old context
389 if (clreleasecontext(glb_ctx) .ne. cl_success) then
390 call neko_error('Failed to release context')
391 end if
392 end if
393
394 glb_ctx = clcreatecontext(c_null_ptr, num_devices, c_loc(glb_device_id), &
395 c_null_funptr, c_null_ptr, ierr)
396
397 if (ierr .ne. cl_success) then
398 call neko_error('Failed to create an OpenCL context')
399 end if
400
401 if (c_associated(glb_cmd_queue)) then
402 if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
403 call neko_error('Faield to release command queue')
404 end if
405 end if
406
407 glb_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
408 queue_props, ierr)
409 if (ierr .ne. cl_success) then
410 call neko_error('Failed to create a command queue')
411 end if
412
413 aux_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
414 queue_props, ierr)
415 if (ierr .ne. cl_success) then
416 call neko_error('Failed to create a command queue')
417 end if
418
419 prf_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
421 if (ierr .ne. cl_success) then
422 call neko_error('Failed to create a command queue')
423 end if
424
425 end subroutine opencl_init
426
427 subroutine opencl_finalize(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
428 type(c_ptr), intent(inout) :: glb_cmd_queue
429 type(c_ptr), intent(inout) :: aux_cmd_queue
430 type(c_ptr), intent(inout) :: prf_cmd_queue
431
432 ! Release all device buffers held by the device layer
433 ! (must precede the release of the context owning them)
435
436 if (c_associated(glb_ctx)) then
437 if (clreleasecontext(glb_ctx) .ne. cl_success) then
438 call neko_error('Failed to release context')
439 end if
440 glb_ctx = c_null_ptr
441 end if
442
443 if (c_associated(glb_cmd_queue)) then
444 if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
445 call neko_error('Failed to release command queue')
446 end if
447 glb_cmd_queue = c_null_ptr
448 end if
449
450 if (c_associated(aux_cmd_queue)) then
451 if (clreleasecommandqueue(aux_cmd_queue) .ne. cl_success) then
452 call neko_error('Failed to release command queue')
453 end if
454 aux_cmd_queue = c_null_ptr
455 end if
456
457 if (c_associated(prf_cmd_queue)) then
458 if (clreleasecommandqueue(prf_cmd_queue) .ne. cl_success) then
459 call neko_error('Failed to release command queue')
460 end if
461 prf_cmd_queue = c_null_ptr
462 end if
463
464 if (c_associated(glb_device_id)) then
465 if (clreleasedevice(glb_device_id) .ne. cl_success) then
466 call neko_error('Failed to release device')
467 end if
468 end if
469
470 end subroutine opencl_finalize
471
472 subroutine opencl_device_name(name)
473 character(len=*), intent(inout) :: name
474 character(kind=c_char, len=1024), target :: c_name
475 integer(c_size_t), target :: name_len
476
477 if (clgetdeviceinfo(glb_device_id, cl_device_name, int(1024, i8), &
478 c_loc(c_name), c_loc(name_len)) .ne. cl_success) then
479 call neko_error('Failed to query device')
480 end if
481
482 name(1:name_len) = c_name(1:name_len)
483
484 end subroutine opencl_device_name
485
487 integer function opencl_device_count()
488 type(c_ptr), target :: platform_id
489 integer(c_int) :: num_platforms, num_devices
490
491 if (clgetplatformids(1, c_loc(platform_id), num_platforms) &
492 .ne. cl_success) then
493 call neko_error('Failed to get a platform id')
494 end if
495
496 if (clgetdeviceids(platform_id, cl_device_type_gpu, 0, &
497 c_null_ptr, num_devices) .ne. cl_success) then
498 call neko_error('Failed to get a device id')
499 end if
500
501 opencl_device_count = num_devices
502
503 end function opencl_device_count
504
509 integer function opencl_device_mp_count()
510 integer(c_int32_t), target :: count
511 integer(c_size_t), target :: ret_size
512
513 count = 0
514 if (clgetdeviceinfo(glb_device_id, cl_device_max_compute_units, &
515 int(c_sizeof(count), c_size_t), c_loc(count), &
516 c_loc(ret_size)) .ne. cl_success) then
517 count = 0
518 end if
519
520 opencl_device_mp_count = int(count)
521
522 end function opencl_device_mp_count
523
526 integer(kind=i8) function opencl_device_total_mem()
527 integer(c_int64_t), target :: mem_size
528 integer(c_size_t), target :: ret_size
529
530 mem_size = 0
531 if (clgetdeviceinfo(glb_device_id, cl_device_global_mem_size, &
532 int(c_sizeof(mem_size), c_size_t), c_loc(mem_size), &
533 c_loc(ret_size)) .ne. cl_success) then
534 mem_size = 0
535 end if
536
537 opencl_device_total_mem = int(mem_size, i8)
538
539 end function opencl_device_total_mem
540#endif
541
542end module opencl_intf
Generic buffer that is extended with buffers of varying rank.
Definition buffer.F90:34
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public i8
Definition num_types.f90:7
Fortran OpenCL interface.
integer(c_int64_t), parameter cl_device_type_default
Device types.
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),...
integer(c_int64_t), parameter cl_device_type_gpu
@ cl_device_global_mem_size
@ 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(c_int64_t), parameter cl_device_type_cpu
@ cl_image_format_mismatch
@ cl_image_format_not_supported
@ cl_device_not_available
@ cl_compiler_not_available
@ cl_mem_object_allocation_failure
@ cl_build_program_failure
@ cl_profiling_info_not_available
integer(c_int64_t), parameter cl_device_type_custom
integer(kind=i8) function opencl_device_total_mem()
Return the global memory size of the current device in bytes (CL_DEVICE_GLOBAL_MEM_SIZE),...
integer(c_int64_t), parameter cl_queue_profiling_enable
integer(c_int64_t), parameter cl_device_type_all
integer(c_int64_t), parameter cl_queue_out_of_order_exec_mode_enable
Queue properties.
integer(c_int64_t), parameter cl_device_type_accelerator
Utilities.
Definition utils.f90:35