FortranCL working example

f90
The ’96 book is still available here, and has some good explanations of numerical mathematics. Oh, the good old times..

Last week I needed to get Fortran working with OpenCL. As the example-page is not up-to-date and not much documentation is on the interwebs outside the official page, this was not as straight-forward as I hoped. The test-suite and this article provided code I could actually use. First I wanted to have things in a module, second I needed to control which device I wanted to use, third I needed function-names that could be used in a larger project. The result is below, and hopefully usable for the Fortran folks around who want to add some OpenCL-kernels to their existing code.

It uses the two-step initialisation we know from C, for safe memory allocation. It is based on the utils.f90 from the test-suite.

The only good way to translate is the Rose-compiler – which is a pain to install. I tried various f2c-scripts (from the 90’s, but they all failed. I must say that continuous switching between Fortran-mode and C-mode was the hardest part of the porting.

If you have tips&tricks to use OpenCL from Fortran, let everybody know in the comments. Also let me know if the code doesn’t work for you, or you have improvements (like better error-handling).

The rest of utils.f90 (which I renamed to clutils.f90 for better integration) is mostly the same – only this subroutine needed changes:

(...)

subroutine cl_initialize(platform_id, device_id, device, context, command_queue)
!use ISO_C_BINDING
type(cl_device_id),     intent(out)     :: device
type(cl_context),       intent(out)     :: context
type(cl_command_queue), intent(out)     :: command_queue
integer                                 :: platform_id
integer                                 :: device_id

integer :: platform_count, device_count, ierr
character(len = 100) :: info
type(cl_platform_id) :: platform
type(cl_platform_id), allocatable, target :: platform_ids(:)
type(cl_device_id), allocatable, target :: device_ids(:)

! get the platform ID
call clGetPlatformIDs(platform_count, ierr)
if(ierr /= CL_SUCCESS) call error_exit('Cannot get CL platform.')
allocate(platform_ids(platform_count))
call clGetPlatformIDs(platform_ids, platform_count, ierr)
if(ierr /= CL_SUCCESS) call error_exit('Cannot get CL platform.')

if (platform_id .gt. platform_count .or. platform_id .lt. 1) platform_id = 0
platform = platform_ids(platform_id)

! get the device ID
call clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, device_count, ierr)
if(ierr /= CL_SUCCESS) call error_exit('Cannot get CL device.')
allocate(device_ids(device_count))
call clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, device_ids, device_count, ierr)
if(ierr /= CL_SUCCESS) call error_exit('Cannot get CL device.')

if (device_id .gt. device_count .or. device_id .lt. 1) device_id = 1
device = device_ids(device_id)

! get the device name and print it
call clGetDeviceInfo(device, CL_DEVICE_NAME, info, ierr)
print*, "CL device: ", info

! create the context and the command queue
context = clCreateContext(platform, device, ierr)
command_queue = clCreateCommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE, ierr)

end subroutine cl_initialize

(...)

It can be called from Fortran 90 like this (based on sum.f90):

module cltest
use cl
use clutils

implicit none

type(cl_device_id) :: device
type(cl_context) :: context
type(cl_command_queue) :: command_queue

contains

subroutine runcltest(clplatform_id, cldevice_num)

    type(cl_kernel) :: kernel
    integer :: data_size, ierr
    integer(8) :: size_in_bytes, globalsize, localsize
    real, allocatable :: vec1(:), vec2(:)
    type(cl_mem) :: cl_vec1, cl_vec2

    INTEGER :: cldevice_num, clplatform_id

    call cl_initialize(clplatform_id, cldevice_num, device, context, command_queue)

(...)

    call clReleaseKernel(kernel, ierr)
    call clReleaseCommandQueue(command_queue, ierr)
    call clReleaseContext(context, ierr)

end subroutine runcltest

end module cltest

The rest of the functions in FortranCL you can find in the reference-wiki.

Ah, the software has has compiled successfully, so I can continue programming. If you find the wrapper useful, don’t forget to thank Xavier Andrade Valencia for creating this wrapper.

Need help with porting Fortran to OpenCL? At StreamHPC can help you to get optimised code.

2 thoughts on “FortranCL working example

  1. Moti

    Hi Vincent,

    We are going to release the CLFORTRAN module as LGPL very soon. It was approved by PRACE to the released to the public and awaiting some other issues.

    You may leave us a notice on the blog post above and I hope to have more updates soon.

    Moti (“Mordechai”).

    • StreamHPC

      Do I understand correctly that the CLFORTRAN you mention, is a higher level version of FortranCL (with lots of util-classes and goodies)? Or is it a new implementation, comparable to?

Comments are closed.