I have been working on creating ArrayFire bindings for Ruby. ArrayFire is an opensource lbrary that is very useful and highly po[ular for GPGPU computings. It has strong abstracts that makes it very easy for a programmer to benefit from GPU without being bothered about the configurations.

I will be creating a blog series regarding that will explain how I created Ruby and JRuby bindings for ArrayFire and how Ruby programmers can use ArrayFire to get free and easy speed improvements with minimum effort. I will start with MRI bindings.

Let the quest begin!

To use ArrayFire, the first thing you need to do is install it.

Installation :

On a Debian machine, I would do

sudo apt-get install libarrayfire-opencl3
sudo apt-get install libarrayfire-opencl-dev

For other OS, you need to checkout this link

Building from source

git clone https://github.com/prasunanand/arrayfire-rb
cd arrayfire-rb
bundle install
rake compile

Installing the gem

gem build arrayfire.gemspec
gem install arrayfire-0.0.0.gem

Now you have got arrayFire installed on the machine, lets check it by running this piece of code in pry. We want to make sure that ArrayFire can detect the GPU devices on our machine.

pry
[1] pry(main)> require 'arrayfire'
=> true
[2] pry(main)> ArrayFire::Device.info()
ArrayFire v3.4.0 (OpenCL, 64-bit Linux, build 75cad40)
[0] NVIDIA  : GeForce GTX 750 Ti, 4041 MB
=> nil
ruby device.rb

This piece of Ruby code will output the GPU devices that are available on your machine.

So, now we get into the implementation:

An introduction to how we setup the project can be found here.

We create the bindings for ArrayFire::Device class;


VALUE Device = Qnil;
static VALUE arf_info(VALUE self);

# Creating the Device class

Device = rb_define_class_under(ArrayFire, "Device", rb_cObject);

# Creating singleton method info

rb_define_singleton_method(Device, "info", (METHOD)arf_info, 0);

static VALUE arf_info(VALUE self){
  #C API to get device info
  af_info();
  return Qnil;
}

Introducing Af_Array

Now, lets have a look at Af_Array. An Af_Array currently expects a two-dimensional array. I have implemented matrix addition and matrix multiplication.

You can try it as follows:

pry
[1] pry(main)> require 'arrayfire'
=> true
[2] pry(main)> a = ArrayFire::Af_Array.new 2, [2,2],[1,2,3,4]
=> #<ArrayFire::Af_Array:0x00000001aa3b50>
[3] pry(main)> b = ArrayFire::Af_Array.new 2, [2,2],[1,2,3,4]
=> #<ArrayFire::Af_Array:0x00000001970738>
[4] pry(main)> c = a + b
=> #<ArrayFire::Af_Array:0x0000000191a1a8>
[5] pry(main)> c.array
=> [2.0, 4.0, 6.0, 8.0]
[6] pry(main)> d = ArrayFire::BLAS.matmul(a,b)
=> #<ArrayFire::Af_Array:0x00000001626258>
[7] pry(main)> d.array
=> [7.0, 10.0, 15.0, 22.0]

Please note that there may be issues with Intel GPUs that don’t support double precision decimals.

Conclusion

We were successfully able to run ArrayFire using Ruby and could detect the GPU hardware available. We were also able to create an Af_Array object. We could add two arrays and also do matrix multiplication.

In the next blog, I would create bindings for Array class and how I implemeted BLAS routines and Arithmetic operations.