Neko  0.8.1
A portable framework for high-order spectral element flow simulations
opencl_intf.F90
Go to the documentation of this file.
1 ! Copyright (c) 2021-2023, 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_cmd_queue = c_null_ptr
44 
46  type(c_ptr), bind(c) :: aux_cmd_queue = c_null_ptr
47 
49  type(c_ptr), bind(c) :: glb_ctx = c_null_ptr
50 
52  type(c_ptr), bind(c), target :: glb_device_id = c_null_ptr
53 
55  enum, bind(c)
56  enumerator :: cl_success = 0
57  enumerator :: cl_device_not_found = -1
58  enumerator :: cl_device_not_available = -2
59  enumerator :: cl_compiler_not_available = -3
61  enumerator :: cl_out_of_resources = -5
62  enumerator :: cl_out_of_host_memory = -6
64  enumerator :: cl_mem_copy_overlap = -8
65  enumerator :: cl_image_format_mismatch = -9
66  enumerator :: cl_image_format_not_supported = -10
67  enumerator :: cl_build_program_failure = -11
68  enumerator :: cl_map_failure = -12
69  end enum
70 
72  enum, bind(c)
73  enumerator :: cl_mem_read_write = 1
74  enumerator :: cl_mem_write_only = 2
75  enumerator :: cl_mem_read_only = 4
76  enumerator :: cl_mem_use_host_ptr = 8
77  enumerator :: cl_mem_alloc_host_ptr = 16
78  enumerator :: cl_mem_host_write_only = 128
79  enumerator :: cl_mem_host_read_only = 256
80  enumerator :: cl_mem_host_no_access = 512
81  end enum
82 
84  enum, bind(c)
85  enumerator :: cl_complete = 0
86  enumerator :: cl_running = 1
87  enumerator :: cl_submitted = 2
88  enumerator :: cl_queued = 3
89  end enum
90 
92  enum, bind(c)
93  enumerator :: cl_false = 0
94  enumerator :: cl_true = 1
95  end enum
96 
97  enum, bind(c)
98  enumerator :: cl_context_platform = int(z'1084')
99  end enum
100 
102  enum, bind(c)
103  enumerator :: cl_device_name = 4139
104  end enum
105 
107  integer(c_int64_t), parameter :: cl_device_type_default = 1
108  integer(c_int64_t), parameter :: cl_device_type_cpu = 2
109  integer(c_int64_t), parameter :: cl_device_type_gpu = 4
110  integer(c_int64_t), parameter :: cl_device_type_accelerator = 8
111  integer(c_int64_t), parameter :: cl_device_type_custom = 16
112  integer(c_int64_t), parameter :: cl_device_type_all = int(z'FFFFFFFF', i8)
113 
114  interface
115  integer (c_int) function clgetplatformids(num_entries, &
116  platforms, 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  end interface
124 
125  interface
126  integer (c_int) function clgetdeviceids(platform, device_type, &
127  num_entries, devices, num_devices) bind(c, name='clGetDeviceIDs')
128  use, intrinsic :: iso_c_binding
129  implicit none
130  type(c_ptr), value :: platform
131  integer(c_int64_t), value :: device_type
132  integer(c_int), value :: num_entries
133  type(c_ptr), value :: devices
134  integer(c_int) :: num_devices
135  end function clgetdeviceids
136  end interface
137 
138  interface
139  type (c_ptr) function clcreatecontext(properties, num_devices, &
140  devices, pfn_notify, user_data, ierr) bind(c, name='clCreateContext')
141  use, intrinsic :: iso_c_binding
142  implicit none
143  type(c_ptr), value :: properties
144  integer(c_int), value :: num_devices
145  type(c_ptr), value :: devices
146  type(c_funptr), value :: pfn_notify
147  type(c_ptr), value :: user_data
148  integer(c_int) :: ierr
149  end function clcreatecontext
150  end interface
151 
152  interface
153  type(c_ptr) function clcreatecommandqueue(context, device, &
154  properties, ierr) bind(c, name='clCreateCommandQueue')
155  use, intrinsic :: iso_c_binding
156  implicit none
157  type(c_ptr), value :: context
158  type(c_ptr), value :: device
159  integer(c_int64_t), value :: properties
160  integer(c_int) :: ierr
161  end function clcreatecommandqueue
162  end interface
163 
164  interface
165  type(c_ptr) function clcreatebuffer(context, flags, size, host_ptr, ierr) &
166  bind(c, name='clCreateBuffer')
167  use, intrinsic :: iso_c_binding
168  implicit none
169  type(c_ptr), value :: context
170  integer(c_int), value :: flags
171  integer(c_size_t), value :: size
172  type(c_ptr), value :: host_ptr
173  integer(c_int) :: ierr
174  end function clcreatebuffer
175  end interface
176 
177  interface
178  type(c_ptr) function clcreateuserevent(context, ierr) &
179  bind(c, name='clCreateUserEvent')
180  use, intrinsic :: iso_c_binding
181  implicit none
182  type(c_ptr), value :: context
183  integer(c_int) :: ierr
184  end function clcreateuserevent
185  end interface
186 
187  interface
188  integer (c_int) function clenqueuereadbuffer(queue, buffer, &
189  blocking_read, offset, size, ptr, num_events_in_wait_list, &
190  event_wait_list, event) bind(c, name='clEnqueueReadBuffer')
191  use, intrinsic :: iso_c_binding
192  implicit none
193  type(c_ptr), value :: queue
194  type(c_ptr), value :: buffer
195  integer(c_int), value :: blocking_read
196  integer(c_size_t), value :: offset
197  integer(c_size_t), value :: size
198  type(c_ptr), value :: ptr
199  integer(c_int), value :: num_events_in_wait_list
200  type(c_ptr), value :: event_wait_list
201  type(c_ptr), value :: event
202  end function clenqueuereadbuffer
203  end interface
204 
205  interface
206  integer (c_int) function clenqueuewritebuffer(queue, buffer, &
207  blocking_write, offset, size, ptr, num_events_in_wait_list, &
208  event_wait_list, event) bind(c, name='clEnqueueWriteBuffer')
209  use, intrinsic :: iso_c_binding
210  implicit none
211  type(c_ptr), value :: queue
212  type(c_ptr), value :: buffer
213  integer(c_int), value :: blocking_write
214  integer(c_size_t), value :: offset
215  integer(c_size_t), value :: size
216  type(c_ptr), value :: ptr
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 clenqueuewritebuffer
221  end interface
222 
223  interface
224  integer (c_int) function clenqueuecopybuffer(queue, src_buffer, &
225  dst_buffer, src_offset, dst_offset, size, num_events_in_wait_list, &
226  event_wait_list, event) bind(c, name='clEnqueueCopyBuffer')
227  use,intrinsic :: iso_c_binding
228  implicit none
229  type(c_ptr), value :: queue
230  type(c_ptr), value :: src_buffer
231  type(c_ptr), value :: dst_buffer
232  integer(c_size_t), value :: src_offset
233  integer(c_size_t), value :: dst_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 clenqueuecopybuffer
239  end interface
240 
241  interface
242  integer (c_int) function clenqueuemarkerwithwaitlist(queue,&
243  num_events_in_wait_list, event_wait_list, event) &
244  bind(c, name='clEnqueueMarkerWithWaitList')
245  use, intrinsic :: iso_c_binding
246  implicit none
247  type(c_ptr), value :: queue
248  integer(c_int), value :: num_events_in_wait_list
249  type(c_ptr), value :: event_wait_list
250  type(c_ptr), value :: event
251  end function clenqueuemarkerwithwaitlist
252  end interface
253 
254  interface
255  integer (c_int) function clenqueuemarker(cmd_queue, event) &
256  bind(c, name='clEnqueueMarker')
257  use, intrinsic :: iso_c_binding
258  implicit none
259  type(c_ptr), value :: cmd_queue
260  type(c_ptr), value :: event
261  end function clenqueuemarker
262  end interface
263 
264  interface
265  integer (c_int) function clenqueuewaitforevents(queue, &
266  num_events, event_list) bind(c, name='clEnqueueWaitForEvents')
267  use, intrinsic :: iso_c_binding
268  implicit none
269  type(c_ptr), value :: queue
270  integer(c_int), value :: num_events
271  type(c_ptr), value :: event_list
272  end function clenqueuewaitforevents
273  end interface
274 
275  interface
276  integer (c_int) function clwaitforevents(num_events, event_list) &
277  bind(c, name='clWaitForEvents')
278  use, intrinsic :: iso_c_binding
279  implicit none
280  integer(c_int), value :: num_events
281  type(c_ptr), value :: event_list
282  end function clwaitforevents
283  end interface
284 
285  interface
286  integer (c_int) function clsetusereventstatus(event, status) &
287  bind(c, name='clSetUserEventStatus')
288  use, intrinsic :: iso_c_binding
289  implicit none
290  type(c_ptr), value :: event
291  integer(c_int), value :: status
292  end function clsetusereventstatus
293  end interface
294 
295  interface
296  integer (c_int) function clgetdeviceinfo(device, param_name, &
297  param_value_size, param_value, param_value_size_ret) &
298  bind(c, name='clGetDeviceInfo')
299  use, intrinsic :: iso_c_binding
300  implicit none
301  type(c_ptr), value :: device
302  integer(c_int), value :: param_name
303  integer(c_size_t), value :: param_value_size
304  type(c_ptr), value :: param_value
305  type(c_ptr), value :: param_value_size_ret
306  end function clgetdeviceinfo
307  end interface
308 
309  interface
310  integer (c_int) function clreleasecontext(context) &
311  bind(c, name='clReleaseContext')
312  use, intrinsic :: iso_c_binding
313  implicit none
314  type(c_ptr), value :: context
315  end function clreleasecontext
316  end interface
317 
318  interface
319  integer (c_int) function clreleasecommandqueue(queue) &
320  bind(c, name='clReleaseCommandQueue')
321  use, intrinsic :: iso_c_binding
322  implicit none
323  type(c_ptr), value :: queue
324  end function clreleasecommandqueue
325  end interface
326 
327  interface
328  integer (c_int) function clreleasedevice(device) &
329  bind(c, name='clReleaseDevice')
330  use, intrinsic :: iso_c_binding
331  implicit none
332  type(c_ptr), value :: device
333  end function clreleasedevice
334  end interface
335 
336  interface
337  integer (c_int) function clreleaseprogram(prgm) &
338  bind(c, name='clReleaseProgram')
339  use, intrinsic :: iso_c_binding
340  implicit none
341  type(c_ptr), value :: prgm
342  end function clreleaseprogram
343  end interface
344 
345  interface
346  integer (c_int) function clreleasememobject(ptr_d) &
347  bind(c, name='clReleaseMemObject')
348  use, intrinsic :: iso_c_binding
349  implicit none
350  type(c_ptr), value :: ptr_d
351  end function clreleasememobject
352  end interface
353 
354  interface
355  integer (c_int) function clreleaseevent(event) &
356  bind(c, name='clReleaseEvent')
357  use, intrinsic :: iso_c_binding
358  implicit none
359  type(c_ptr), value :: event
360  end function clreleaseevent
361  end interface
362 
363  interface
364  integer (c_int) function clflush(cmd_queue) &
365  bind(c, name='clFlush')
366  use, intrinsic :: iso_c_binding
367  implicit none
368  type(c_ptr), value :: cmd_queue
369  end function clflush
370  end interface
371 
372  interface
373  integer (c_int) function clfinish(cmd_queue) &
374  bind(c, name='clFinish')
375  use, intrinsic :: iso_c_binding
376  implicit none
377  type(c_ptr), value :: cmd_queue
378  end function clfinish
379  end interface
380 
381 contains
382 
383  subroutine opencl_init
384  type(c_ptr), target :: platform_id
385  integer(c_int) :: num_platforms, num_devices, ierr
386  integer(c_intptr_t) :: ctx_prop(3)
387  integer(c_int64_t), parameter :: queue_props = 0
388  integer :: i
389 
390  if (clgetplatformids(1, c_loc(platform_id), &
391  num_platforms) .ne. cl_success) then
392  call neko_error('Failed to get a platform id')
393  end if
394 
395  if (clgetdeviceids(platform_id, cl_device_type_gpu, 1, &
396  c_loc(glb_device_id), num_devices) .ne. cl_success) then
397  call neko_error('Failed to get a device id')
398  end if
399 
400  if (c_associated(glb_ctx)) then
401  if (clreleasecontext(glb_ctx) .ne. cl_success) then
402  call neko_error('Failed to release context')
403  end if
404  end if
405 
406  glb_ctx = clcreatecontext(c_null_ptr, num_devices, c_loc(glb_device_id), &
407  c_null_funptr, c_null_ptr, ierr)
408 
409  if (ierr .ne. cl_success) then
410  call neko_error('Failed to create an OpenCL context')
411  end if
412 
413  if (c_associated(glb_cmd_queue)) then
414  if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
415  call neko_error('Faield to release command queue')
416  end if
417  end if
418 
419  glb_cmd_queue = clcreatecommandqueue(glb_ctx, glb_device_id, queue_props, ierr)
420 
421  if (ierr .ne. cl_success) then
422  call neko_error('Failed to create a command queue')
423  end if
424 
425  ! Currently we only have one "queue" for the OpenCL backend
426  aux_cmd_queue = glb_cmd_queue
427 
428  end subroutine opencl_init
429 
430  subroutine opencl_finalize
431 
432  if (c_associated(glb_ctx)) then
433  if (clreleasecontext(glb_ctx) .ne. cl_success) then
434  call neko_error('Failed to release context')
435  end if
436  glb_ctx = c_null_ptr
437  end if
438 
439  if (c_associated(glb_cmd_queue)) then
440  if (clreleasecommandqueue(glb_cmd_queue) .ne. cl_success) then
441  call neko_error('Faield to release command queue')
442  end if
443  glb_cmd_queue = c_null_ptr
444  end if
445 
446  if (c_associated(glb_device_id)) then
447  if (clreleasedevice(glb_device_id) .ne. cl_success) then
448  call neko_error('Faield to release device')
449  end if
450  end if
451 
452  end subroutine opencl_finalize
453 
454  subroutine opencl_device_name(name)
455  character(len=*), intent(inout) :: name
456  character(kind=c_char, len=1024), target :: c_name
457  integer(c_size_t), target :: name_len
458 
459  if (clgetdeviceinfo(glb_device_id, cl_device_name, int(1024, i8), &
460  c_loc(c_name), c_loc(name_len)) .ne. cl_success) then
461  call neko_error('Failed to query device')
462  end if
463 
464  name(1:name_len) = c_name(1:name_len)
465 
466  end subroutine opencl_device_name
467 
468 #endif
469 
470 end module opencl_intf
Device abstraction, common interface for various accelerators.
Definition: device.F90:34
integer, parameter, public i8
Definition: num_types.f90:7
Fortran OpenCL interface.
Definition: opencl_intf.F90:34
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
type(c_ptr), bind(C) aux_cmd_queue
Aux OpenCL command queue.
Definition: opencl_intf.F90:46
subroutine opencl_init
@ cl_mem_host_no_access
Definition: opencl_intf.F90:80
@ cl_mem_host_write_only
Definition: opencl_intf.F90:78
@ cl_mem_alloc_host_ptr
Definition: opencl_intf.F90:77
@ cl_mem_host_read_only
Definition: opencl_intf.F90:79
subroutine opencl_finalize
integer(c_int64_t), parameter cl_device_type_cpu
@ cl_image_format_mismatch
Definition: opencl_intf.F90:65
@ cl_image_format_not_supported
Definition: opencl_intf.F90:66
@ cl_out_of_host_memory
Definition: opencl_intf.F90:62
@ cl_device_not_available
Definition: opencl_intf.F90:58
@ cl_compiler_not_available
Definition: opencl_intf.F90:59
@ cl_mem_object_allocation_failure
Definition: opencl_intf.F90:60
@ cl_build_program_failure
Definition: opencl_intf.F90:67
@ cl_profiling_info_not_available
Definition: opencl_intf.F90:63
integer(c_int64_t), parameter cl_device_type_custom
integer(c_int64_t), parameter cl_device_type_all
integer(c_int64_t), parameter cl_device_type_accelerator
Utilities.
Definition: utils.f90:35