Neko 1.99.3
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 end interface
357
358contains
359
360 subroutine opencl_init(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
361 type(c_ptr), intent(inout) :: glb_cmd_queue
362 type(c_ptr), intent(inout) :: aux_cmd_queue
363 type(c_ptr), intent(inout) :: prf_cmd_queue
364 type(c_ptr), target :: platform_id
365 integer(c_int) :: num_platforms, num_devices, ierr
366 integer(c_intptr_t) :: ctx_prop(3)
367 integer(c_int64_t), parameter :: queue_props = 0
368 integer :: i
369
370 if (clgetplatformids(1, c_loc(platform_id), &
371 num_platforms) .ne. cl_success) then
372 call neko_error('Failed to get a platform id')
373 end if
374
375 if (clgetdeviceids(platform_id, cl_device_type_gpu, 1, &
376 c_loc(glb_device_id), num_devices) .ne. cl_success) then
377 call neko_error('Failed to get a device id')
378 end if
379
380 if (c_associated(glb_ctx)) then
381 if (clreleasecontext(glb_ctx) .ne. cl_success) then
382 call neko_error('Failed to release context')
383 end if
384 end if
385
386 glb_ctx = clcreatecontext(c_null_ptr, num_devices, c_loc(glb_device_id), &
387 c_null_funptr, c_null_ptr, ierr)
388
389 if (ierr .ne. cl_success) then
390 call neko_error('Failed to create an OpenCL context')
391 end if
392
393 if (c_associated(glb_cmd_queue)) then
394 if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
395 call neko_error('Faield to release command queue')
396 end if
397 end if
398
399 glb_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
400 queue_props, ierr)
401 if (ierr .ne. cl_success) then
402 call neko_error('Failed to create a command queue')
403 end if
404
405 aux_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 prf_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, &
413 if (ierr .ne. cl_success) then
414 call neko_error('Failed to create a command queue')
415 end if
416
417 end subroutine opencl_init
418
419 subroutine opencl_finalize(glb_cmd_queue, aux_cmd_queue, prf_cmd_queue)
420 type(c_ptr), intent(inout) :: glb_cmd_queue
421 type(c_ptr), intent(inout) :: aux_cmd_queue
422 type(c_ptr), intent(inout) :: prf_cmd_queue
423
424 if (c_associated(glb_ctx)) then
425 if (clreleasecontext(glb_ctx) .ne. cl_success) then
426 call neko_error('Failed to release context')
427 end if
428 glb_ctx = c_null_ptr
429 end if
430
431 if (c_associated(glb_cmd_queue)) then
432 if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
433 call neko_error('Failed to release command queue')
434 end if
435 glb_cmd_queue = c_null_ptr
436 end if
437
438 if (c_associated(aux_cmd_queue)) then
439 if (clreleasecommandqueue(aux_cmd_queue) .ne. cl_success) then
440 call neko_error('Failed to release command queue')
441 end if
442 aux_cmd_queue = c_null_ptr
443 end if
444
445 if (c_associated(prf_cmd_queue)) then
446 if (clreleasecommandqueue(prf_cmd_queue) .ne. cl_success) then
447 call neko_error('Failed to release command queue')
448 end if
449 prf_cmd_queue = c_null_ptr
450 end if
451
452 if (c_associated(glb_device_id)) then
453 if (clreleasedevice(glb_device_id) .ne. cl_success) then
454 call neko_error('Failed to release device')
455 end if
456 end if
457
458 end subroutine opencl_finalize
459
460 subroutine opencl_device_name(name)
461 character(len=*), intent(inout) :: name
462 character(kind=c_char, len=1024), target :: c_name
463 integer(c_size_t), target :: name_len
464
465 if (clgetdeviceinfo(glb_device_id, cl_device_name, int(1024, i8), &
466 c_loc(c_name), c_loc(name_len)) .ne. cl_success) then
467 call neko_error('Failed to query device')
468 end if
469
470 name(1:name_len) = c_name(1:name_len)
471
472 end subroutine opencl_device_name
473
475 integer function opencl_device_count()
476 type(c_ptr), target :: platform_id
477 integer(c_int) :: num_platforms, num_devices
478
479 if (clgetplatformids(1, c_loc(platform_id), num_platforms) &
480 .ne. cl_success) then
481 call neko_error('Failed to get a platform id')
482 end if
483
484 if (clgetdeviceids(platform_id, cl_device_type_gpu, 0, &
485 c_null_ptr, num_devices) .ne. cl_success) then
486 call neko_error('Failed to get a device id')
487 end if
488
489 opencl_device_count = num_devices
490
491 end function opencl_device_count
492#endif
493
494end 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