Neko 1.99.6
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_name = 4139
98 end enum
99
101 integer(c_int64_t), parameter :: cl_device_type_default = 1
102 integer(c_int64_t), parameter :: cl_device_type_cpu = 2
103 integer(c_int64_t), parameter :: cl_device_type_gpu = 4
104 integer(c_int64_t), parameter :: cl_device_type_accelerator = 8
105 integer(c_int64_t), parameter :: cl_device_type_custom = 16
106 integer(c_int64_t), parameter :: cl_device_type_all = int(z'FFFFFFFF', i8)
107
109 integer(c_int64_t), parameter :: cl_queue_out_of_order_exec_mode_enable = 1
110 integer(c_int64_t), parameter :: cl_queue_profiling_enable = 2
111
112 interface
113 integer(c_int) function clgetplatformids(num_entries, platforms, &
114 num_platforms) bind(c, name = 'clGetPlatformIDs')
115 use, intrinsic :: iso_c_binding
116 implicit none
117 integer(c_int), value :: num_entries
118 type(c_ptr), value :: platforms
119 integer(c_int) :: num_platforms
120 end function clgetplatformids
121
122 integer(c_int) function clgetdeviceids(platform, device_type, &
123 num_entries, devices, num_devices) bind(c, name = 'clGetDeviceIDs')
124 use, intrinsic :: iso_c_binding
125 implicit none
126 type(c_ptr), value :: platform
127 integer(c_int64_t), value :: device_type
128 integer(c_int), value :: num_entries
129 type(c_ptr), value :: devices
130 integer(c_int) :: num_devices
131 end function clgetdeviceids
132
133 type (c_ptr) function clcreatecontext(properties, num_devices, devices, &
134 pfn_notify, user_data, ierr) bind(c, name = 'clCreateContext')
135 use, intrinsic :: iso_c_binding
136 implicit none
137 type(c_ptr), value :: properties
138 integer(c_int), value :: num_devices
139 type(c_ptr), value :: devices
140 type(c_funptr), value :: pfn_notify
141 type(c_ptr), value :: user_data
142 integer(c_int) :: ierr
143 end function clcreatecontext
144
145 type(c_ptr) function clcreatecommandqueue(context, device, &
146 properties, ierr) bind(c, name = 'clCreateCommandQueue')
147 use, intrinsic :: iso_c_binding
148 implicit none
149 type(c_ptr), value :: context
150 type(c_ptr), value :: device
151 integer(c_int64_t), value :: properties
152 integer(c_int) :: ierr
153 end function clcreatecommandqueue
154
155 type(c_ptr) function clcreatebuffer(context, flags, size, host_ptr, ierr) &
156 bind(c, name = 'clCreateBuffer')
157 use, intrinsic :: iso_c_binding
158 implicit none
159 type(c_ptr), value :: context
160 integer(c_int), value :: flags
161 integer(c_size_t), value :: size
162 type(c_ptr), value :: host_ptr
163 integer(c_int) :: ierr
164 end function clcreatebuffer
165
166 type(c_ptr) function clcreateuserevent(context, ierr) &
167 bind(c, name = 'clCreateUserEvent')
168 use, intrinsic :: iso_c_binding
169 implicit none
170 type(c_ptr), value :: context
171 integer(c_int) :: ierr
172 end function clcreateuserevent
173
174 integer(c_int) function clenqueuereadbuffer(queue, buffer, blocking_read, &
175 offset, size, ptr, num_events_in_wait_list, event_wait_list, event) &
176 bind(c, name = 'clEnqueueReadBuffer')
177 use, intrinsic :: iso_c_binding
178 implicit none
179 type(c_ptr), value :: queue
180 type(c_ptr), value :: buffer
181 integer(c_int), value :: blocking_read
182 integer(c_size_t), value :: offset
183 integer(c_size_t), value :: size
184 type(c_ptr), value :: ptr
185 integer(c_int), value :: num_events_in_wait_list
186 type(c_ptr), value :: event_wait_list
187 type(c_ptr), value :: event
188 end function clenqueuereadbuffer
189
190 integer(c_int) function clenqueuewritebuffer(queue, buffer, &
191 blocking_write, offset, size, ptr, num_events_in_wait_list, &
192 event_wait_list, event) bind(c, name = 'clEnqueueWriteBuffer')
193 use, intrinsic :: iso_c_binding
194 implicit none
195 type(c_ptr), value :: queue
196 type(c_ptr), value :: buffer
197 integer(c_int), value :: blocking_write
198 integer(c_size_t), value :: offset
199 integer(c_size_t), value :: size
200 type(c_ptr), value :: ptr
201 integer(c_int), value :: num_events_in_wait_list
202 type(c_ptr), value :: event_wait_list
203 type(c_ptr), value :: event
204 end function clenqueuewritebuffer
205
206 integer(c_int) function clenqueuecopybuffer(queue, src_buffer, &
207 dst_buffer, src_offset, dst_offset, size, num_events_in_wait_list, &
208 event_wait_list, event) bind(c, name = 'clEnqueueCopyBuffer')
209 use, intrinsic :: iso_c_binding
210 implicit none
211 type(c_ptr), value :: queue
212 type(c_ptr), value :: src_buffer
213 type(c_ptr), value :: dst_buffer
214 integer(c_size_t), value :: src_offset
215 integer(c_size_t), value :: dst_offset
216 integer(c_size_t), value :: size
217 integer(c_int), value :: num_events_in_wait_list
218 type(c_ptr), value :: event_wait_list
219 type(c_ptr), value :: event
220 end function clenqueuecopybuffer
221
222 integer(c_int) function clenqueuefillbuffer(queue, buffer, &
223 pattern, pattern_size, offset, size, num_events_in_wait_list, &
224 event_wait_list, event) bind(c, name = 'clEnqueueFillBuffer')
225 use, intrinsic :: iso_c_binding
226 implicit none
227 type(c_ptr), value :: queue
228 type(c_ptr), value :: buffer
229 type(c_ptr), value :: pattern
230 integer(c_size_t), value :: pattern_size
231 integer(c_size_t), value :: offset
232 integer(c_size_t), value :: size
233 integer(c_int), value :: num_events_in_wait_list
234 type(c_ptr), value :: event_wait_list
235 type(c_ptr), value :: event
236 end function clenqueuefillbuffer
237
238 integer(c_int) function clenqueuemarkerwithwaitlist &
239 (queue, num_events_in_wait_list, event_wait_list, event) &
240 bind(c, name = 'clEnqueueMarkerWithWaitList')
241 use, intrinsic :: iso_c_binding
242 implicit none
243 type(c_ptr), value :: queue
244 integer(c_int), value :: num_events_in_wait_list
245 type(c_ptr), value :: event_wait_list
246 type(c_ptr), value :: event
247 end function clenqueuemarkerwithwaitlist
248
249 integer(c_int) function clenqueuemarker(cmd_queue, event) &
250 bind(c, name = 'clEnqueueMarker')
251 use, intrinsic :: iso_c_binding
252 implicit none
253 type(c_ptr), value :: cmd_queue
254 type(c_ptr), value :: event
255 end function clenqueuemarker
256
257 integer(c_int) function clenqueuebarrier(cmd_queue) &
258 bind(c, name = 'clEnqueueBarrier')
259 use, intrinsic :: iso_c_binding
260 implicit none
261 type(c_ptr), value :: cmd_queue
262 end function clenqueuebarrier
263
264 integer(c_int) function clenqueuewaitforevents(queue, &
265 num_events, event_list) bind(c, name = 'clEnqueueWaitForEvents')
266 use, intrinsic :: iso_c_binding
267 implicit none
268 type(c_ptr), value :: queue
269 integer(c_int), value :: num_events
270 type(c_ptr), value :: event_list
271 end function clenqueuewaitforevents
272
273 integer(c_int) function clwaitforevents(num_events, event_list) &
274 bind(c, name = 'clWaitForEvents')
275 use, intrinsic :: iso_c_binding
276 implicit none
277 integer(c_int), value :: num_events
278 type(c_ptr), value :: event_list
279 end function clwaitforevents
280
281 integer(c_int) function clsetusereventstatus(event, status) &
282 bind(c, name = 'clSetUserEventStatus')
283 use, intrinsic :: iso_c_binding
284 implicit none
285 type(c_ptr), value :: event
286 integer(c_int), value :: status
287 end function clsetusereventstatus
288
289 integer(c_int) function clgetdeviceinfo(device, param_name, &
290 param_value_size, param_value, param_value_size_ret) &
291 bind(c, name = 'clGetDeviceInfo')
292 use, intrinsic :: iso_c_binding
293 implicit none
294 type(c_ptr), value :: device
295 integer(c_int), value :: param_name
296 integer(c_size_t), value :: param_value_size
297 type(c_ptr), value :: param_value
298 type(c_ptr), value :: param_value_size_ret
299 end function clgetdeviceinfo
300
301 integer(c_int) function clreleasecontext(context) &
302 bind(c, name = 'clReleaseContext')
303 use, intrinsic :: iso_c_binding
304 implicit none
305 type(c_ptr), value :: context
306 end function clreleasecontext
307
308 integer(c_int) function clreleasecommandqueue(queue) &
309 bind(c, name = 'clReleaseCommandQueue')
310 use, intrinsic :: iso_c_binding
311 implicit none
312 type(c_ptr), value :: queue
313 end function clreleasecommandqueue
314
315 integer(c_int) function clreleasedevice(device) &
316 bind(c, name = 'clReleaseDevice')
317 use, intrinsic :: iso_c_binding
318 implicit none
319 type(c_ptr), value :: device
320 end function clreleasedevice
321
322 integer(c_int) function clreleaseprogram(prgm) &
323 bind(c, name = 'clReleaseProgram')
324 use, intrinsic :: iso_c_binding
325 implicit none
326 type(c_ptr), value :: prgm
327 end function clreleaseprogram
328
329 integer(c_int) function clreleasememobject(ptr_d) &
330 bind(c, name = 'clReleaseMemObject')
331 use, intrinsic :: iso_c_binding
332 implicit none
333 type(c_ptr), value :: ptr_d
334 end function clreleasememobject
335
336 integer(c_int) function clreleaseevent(event) &
337 bind(c, name = 'clReleaseEvent')
338 use, intrinsic :: iso_c_binding
339 implicit none
340 type(c_ptr), value :: event
341 end function clreleaseevent
342
343 integer(c_int) function clflush(cmd_queue) &
344 bind(c, name = 'clFlush')
345 use, intrinsic :: iso_c_binding
346 implicit none
347 type(c_ptr), value :: cmd_queue
348 end function clflush
349
350 integer(c_int) function clfinish(cmd_queue) &
351 bind(c, name = 'clFinish')
352 use, intrinsic :: iso_c_binding
353 implicit none
354 type(c_ptr), value :: cmd_queue
355 end function clfinish
356
358 bind(c, name = 'opencl_buffer_free_all')
359 end subroutine opencl_buffer_free_all
360 end interface
361
362contains
363
364 subroutine opencl_init(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
365 type(c_ptr), intent(inout) :: glb_cmd_queue
366 type(c_ptr), intent(inout) :: aux_cmd_queue
367 type(c_ptr), intent(inout) :: prf_cmd_queue
368 type(c_ptr), target :: platform_id
369 integer(c_int) :: num_platforms, num_devices, ierr
370 integer(c_intptr_t) :: ctx_prop(3)
371 integer(c_int64_t), parameter :: queue_props = 0
372 integer :: i
373
374 if (clgetplatformids(1, c_loc(platform_id), &
375 num_platforms) .ne. cl_success) then
376 call neko_error('Failed to get a platform id')
377 end if
378
379 if (clgetdeviceids(platform_id, cl_device_type_gpu, 1, &
380 c_loc(glb_device_id), num_devices) .ne. cl_success) then
381 call neko_error('Failed to get a device id')
382 end if
383
384 if (c_associated(glb_ctx)) then
385 ! Release all device buffers created against the old context
387 if (clreleasecontext(glb_ctx) .ne. cl_success) then
388 call neko_error('Failed to release context')
389 end if
390 end if
391
392 glb_ctx = clcreatecontext(c_null_ptr, num_devices, c_loc(glb_device_id), &
393 c_null_funptr, c_null_ptr, ierr)
394
395 if (ierr .ne. cl_success) then
396 call neko_error('Failed to create an OpenCL context')
397 end if
398
399 if (c_associated(glb_cmd_queue)) then
400 if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
401 call neko_error('Faield to release command queue')
402 end if
403 end if
404
405 glb_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
406 queue_props, ierr)
407 if (ierr .ne. cl_success) then
408 call neko_error('Failed to create a command queue')
409 end if
410
411 aux_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
412 queue_props, ierr)
413 if (ierr .ne. cl_success) then
414 call neko_error('Failed to create a command queue')
415 end if
416
417 prf_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
419 if (ierr .ne. cl_success) then
420 call neko_error('Failed to create a command queue')
421 end if
422
423 end subroutine opencl_init
424
425 subroutine opencl_finalize(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
426 type(c_ptr), intent(inout) :: glb_cmd_queue
427 type(c_ptr), intent(inout) :: aux_cmd_queue
428 type(c_ptr), intent(inout) :: prf_cmd_queue
429
430 ! Release all device buffers held by the device layer
431 ! (must precede the release of the context owning them)
433
434 if (c_associated(glb_ctx)) then
435 if (clreleasecontext(glb_ctx) .ne. cl_success) then
436 call neko_error('Failed to release context')
437 end if
438 glb_ctx = c_null_ptr
439 end if
440
441 if (c_associated(glb_cmd_queue)) then
442 if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
443 call neko_error('Failed to release command queue')
444 end if
445 glb_cmd_queue = c_null_ptr
446 end if
447
448 if (c_associated(aux_cmd_queue)) then
449 if (clreleasecommandqueue(aux_cmd_queue) .ne. cl_success) then
450 call neko_error('Failed to release command queue')
451 end if
452 aux_cmd_queue = c_null_ptr
453 end if
454
455 if (c_associated(prf_cmd_queue)) then
456 if (clreleasecommandqueue(prf_cmd_queue) .ne. cl_success) then
457 call neko_error('Failed to release command queue')
458 end if
459 prf_cmd_queue = c_null_ptr
460 end if
461
462 if (c_associated(glb_device_id)) then
463 if (clreleasedevice(glb_device_id) .ne. cl_success) then
464 call neko_error('Failed to release device')
465 end if
466 end if
467
468 end subroutine opencl_finalize
469
470 subroutine opencl_device_name(name)
471 character(len=*), intent(inout) :: name
472 character(kind=c_char, len=1024), target :: c_name
473 integer(c_size_t), target :: name_len
474
475 if (clgetdeviceinfo(glb_device_id, cl_device_name, int(1024, i8), &
476 c_loc(c_name), c_loc(name_len)) .ne. cl_success) then
477 call neko_error('Failed to query device')
478 end if
479
480 name(1:name_len) = c_name(1:name_len)
481
482 end subroutine opencl_device_name
483
485 integer function opencl_device_count()
486 type(c_ptr), target :: platform_id
487 integer(c_int) :: num_platforms, num_devices
488
489 if (clgetplatformids(1, c_loc(platform_id), num_platforms) &
490 .ne. cl_success) then
491 call neko_error('Failed to get a platform id')
492 end if
493
494 if (clgetdeviceids(platform_id, cl_device_type_gpu, 0, &
495 c_null_ptr, num_devices) .ne. cl_success) then
496 call neko_error('Failed to get a device id')
497 end if
498
499 opencl_device_count = num_devices
500
501 end function opencl_device_count
502#endif
503
504end 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(c_int64_t), parameter cl_device_type_gpu
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(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