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