As <a title="ArrayFire function list" href="http://www.sandbox.arrayfire.com/docs/group__arrayfire__func.htm" target="_blank">extensive</a> as ArrayFire is, there are a few cases where you are still working with custom CUDA or OpenCL kernels. You may want to integrate ArrayFire into an existing code base for productivity or you may want to keep around the old implementation for testing purposes. In this post we are going to talk about how you can integrate your custom kernels into ArrayFire in a seamless fashion.

First let us look at the code and then break it down bit by bit.
<pre>int main()
{
    af::array x = af::randu(num, 1);

    af::array y = af::array(num, 1);

    float *d_x = x.device();
    float *d_y = y.device();

    af::sync();

    launch_simple_kernel(d_y, d_x, num);
    x.unlock();
    y.unlock();

    float err = af::sum(y - 1);
    printf("Error: %f\n", err);
    return 0;
}
</pre>
Firstly you need an input to the kernel. 

<pre>
// Generate input data
af::array x = af::randu(num, 1);
</pre>

In this case, it is the variable <strong> x </strong> that has been created as a uniformly random array. If you have data coming from other computations, you can use that instead.

The necessary memory required for the output needs to be allocated before we launch the kernel. 
<pre>
// Create empty array with required dimensions
af::array y = af::array(num, 1);
</pre>
In this sample, the output <string> y </strong> has the same number of elements as <strong> x </strong>. Note that we are not specifying the output data type. In such cases ArrayFire assumes the data type is single precision floating point (<strong> af::f32 </strong>). You can add the necessary data type at the end of the <strong> array(..)</strong> constructor.

Once you have the input and output arrays, you will need to extract the device pointers / objects using the following manner.
<pre>
 // Get device pointers
 float *d_x = x.device<float>();
 float *d_y = y.device<float>();
</pre>

Before you launch your custom kernel, it would be best to make sure all the computations performed by ArrayFire have finished. This can be called by using <strong> af::sync(); </strong>
<pre>
// Finish the tasks arrayfire was doing
af::sync();

// Launch kernel to do the following operations
// y = sin(x)^2 + con(x)^2
launch_simple_kernel(d_y, d_x, num);
</pre>

The function <strong> launch_simple_kernel </strong> will handle the launching of your custom kernel. We will have a look at how to do this in CUDA and OpenCL later in the post.

Once you have finished your computations, you have to tell ArrayFire to take control of the memory objects. 
<pre>
// Tell arrayfire it controls the pointers again
x.unlock();
y.unlock();
</pre>
This is a very crucial step because if ArrayFire believes the user still controls the pointer, it does not perform garbage collection on those arrays and will potentially lead to memory leaks.

You can now proceed with the rest of the program. In our particular example, we are just performing an error check and exiting.
<pre>
// Check for errors
// sin(x)^ + cos(x)^2 == 1
// The following should print 0
float err = af::sum<float>(y - 1);
printf("Error: %f\n", err);
</pre>