Fortran Interop Use Case#

Operations on multidimensional fortran allocated arrays using Kokkos#

This example demonstrates usage of the Fortran Language Compatibility Layer (FLCL) in the context of performing a DAXPY (double precision A * X + Y) using Kokkos from a simple fortran program. Such a use case occurs when using Kokkos for performance portability within a Fortran application.

Program structure#

This example uses the Kokkos fortran interop utilities in FLCL. This includes a set of fortran routines for converting fortran allocated arrays into a ndarray and a set of C++ functions for converting a ndarray into a Kokkos unmanaged view.

The ndarray type (flcl_ndarray_t) is a simple struct that captures the rank, dimensions, strides (equivalent to a dope vector) along with the flattened data. This is defined and implemented in flcl-cxx.hpp

typedef struct _flcl_nd_array_t {
    size_t rank;
    size_t dims[FLCL_NDARRAY_MAX_RANK];
    size_t strides[FLCL_NDARRAY_MAX_RANK];
    void *data;
} flcl_ndarray_t;

This has a fortran equivalent type located in flcl-f.f90

type, bind(C) :: nd_array_t
    integer(c_size_t) :: rank
    integer(c_size_t) :: dims(ND_ARRAY_MAX_RANK)
    integer(c_size_t) :: strides(ND_ARRAY_MAX_RANK)
    type(c_ptr) :: data
  end type nd_array_t

To convert a fortran allocated array into a ndarray we use a set of procedures (behind an interface) defined in flcl-f.f90

interface to_nd_array
    ! 1D specializations
    module procedure to_nd_array_l_1d
    module procedure to_nd_array_i32_1d
    module procedure to_nd_array_i64_1d
    module procedure to_nd_array_r32_1d
    module procedure to_nd_array_r64_1d
    ! 2D specializations
    module procedure to_nd_array_l_2d
    module procedure to_nd_array_i32_2d
    module procedure to_nd_array_i64_2d
    module procedure to_nd_array_r32_2d
    module procedure to_nd_array_r64_2d

    ! 3D specializations
    module procedure to_nd_array_l_3d
    module procedure to_nd_array_i32_3d
    module procedure to_nd_array_i64_3d
    module procedure to_nd_array_r32_3d
    module procedure to_nd_array_r64_3d

To convert a ndarray to a Kokkos::View we use view_from_ndarray defined in flcl-cxx.hpp

template <typename DataType>
  Kokkos::View<DataType, Kokkos::LayoutStride, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>
  view_from_ndarray(flcl_ndarray_t const &ndarray) 

These are the main utilities that will be used in our DAXPY example.

We begin with a fortran program defined in axpy-main.f90

We start by bringing in the flcl module:

use :: flcl_mod

We then define our arrays including two ‘Y’ arrays, one will be used for calculating the daxpy result with fortran, the other with kokkos.

  real(c_double), dimension(:), allocatable :: f_y
  real(c_double), dimension(:), allocatable :: c_y
  real(c_double), dimension(:), allocatable :: x
  real(c_double) :: alpha

Performing the DAXPY in fortran is simply:

do ii = 1, mm
    f_y(ii) = f_y(ii) + alpha * x(ii)
  end do

Performing the DAXPY in Kokkos begins with a call to axpy:

call axpy(c_y, x, alpha)

This is defined in axpy-f.90

subroutine axpy( y, x, alpha )
          use, intrinsic :: iso_c_binding
          use :: flcl_mod
          implicit none
          real(c_double), dimension(:), intent(inout) :: y
          real(c_double), dimension(:), intent(in) :: x
          real(c_double), intent(in) :: alpha

          call f_axpy(to_nd_array(y), to_nd_array(x), alpha)

        end subroutine axpy

Which calls the subroutine f_axpy but prior to doing so converts the fortran arrays into nd_arrays. f_axpy is defined earlier and note that f_axpy is bound to the C routine ‘c_axpy’.

        subroutine f_axpy( nd_array_y, nd_array_x, alpha ) &
          & bind(c, name='c_axpy')
          use, intrinsic :: iso_c_binding
          use :: flcl_mod
          type(nd_array_t) :: nd_array_y
          type(nd_array_t) :: nd_array_x
          real(c_double) :: alpha
        end subroutine f_axpy
      end interface

c_axpy is where we make use of Kokkos for the computation and is defined in

void c_axpy( flcl_ndarray_t *nd_array_y, flcl_ndarray_t *nd_array_x, double *alpha ) {
    using flcl::view_from_ndarray;

    auto y = view_from_ndarray<double*>(*nd_array_y);
    auto x = view_from_ndarray<double*>(*nd_array_x);

    Kokkos::parallel_for( "axpy", y.extent(0), KOKKOS_LAMBDA( const size_t idx)
      y(idx) += *alpha * x(idx);

In this function we first convert our two nd_array to Kokkos::View and then use Kokkos::parallel_for with a simply DAXPY lambda.

This use case illustrates the ability to use Kokkos in fortran applications with interoperability of fortran arrays and Kokkos::View via the ndarray type and conversion routines provided in FLCL.