ScalaCL: Reap OpenCL's benefits without learning its syntax (Scala DSL for transparently parallel computations)

In my previous post I introduced OpenCL4Java, a new library I wrote to make it relatively easy to use OpenCL from Java.

Today I’ll present you ScalaCL, which goes a step further in Scala(if you haven’t jumped in the Scala train yet, now is the time to do it !)



ScalaCL is a library that makes it trivial to evaluate simple parallel expressions in Scala.

<Useless Technical Jargon On>
Technically, ScalaCL is an internal DSL (see Domain Specific Language) that creates OpenCL kernels out of its internal AST-like representation and executes them through the OpenCL4Java OO bindings (which in turn use JNA + JNAerator to call OpenCL’s C API
</Useless Technical Jargon Off>

A common OpenCL example you can find on the web is the “vector add” (see ATI doc, Python::OpenCL…)
Here’s how it looks like in ScalaCL :


import scalacl._
import scalacl.ScalaCL._

class VectAdd(i: Dim) extends Program(i) {
val a = FloatsVar // array of floats
val b = FloatsVar
var output = FloatsVar
content = output := a + b
// Or some more useful content :
// content = output := a * sin(b) + 1
}

var n = 1000;
var prog = new MyProg(n)
prog.a.write(1 to n)
prog.b.write(prog.a)
prog ! // run the operation
println prog.output // print the output

Here we simply have arrays of “a” and “b” float values and for each position i in the arrays we want to compute “output[i] = a[i] * b[i]“.

The cool thing here is this gets executed transparently in parallel on the graphic card (or on your GPU, depending on your OpenCL environment). Yes, that’s parallelization for free !

Notice the “:=” operator to express assignment of some expression to a variable.

Note that :

content = output := a * sin(b) + 1

would be strictly equivalent to

content = output(i) := a(i) * sin(b(i)) + 1

The size and array index of the a and b array variables are here automatically inferred by ScalaCL to that of the only declared dimension of execution of the program (an OpenCL kernel can execute on an arbitrary number of dimensions, which is useful to process 2D or 3D images).

Of course, the size of the arrays can also be specified by hand, and this is actually needed when there are more than one dimension of execution :

class SomeProg(x: Dim, y: Dim) extends Program(x, y) {
val someBuf = IntsVar(10)
val someOtherBuf = IntsVar(y) // buffer as large as the y dimension
content = ...
}

In this last example, the program will execute on a 2-dimensional basis (equivalent to evaluating its content in a for (int x …) for (int y …) loop).

However, the preferred way is to let ScalaCL guess the size of input and output arrays, even when in non-trivial cases :

class VectSinCos(i: Dim) extends Program(i) {
val x = FloatsVar
val sincosx = FloatsVar
content = List(
sincosx(i * 2) := sin(x),
sincosx(i * 2 + 1) := cos(x)
)
}

Here, the result “sincosx” array will contain interleaved sin and cos values for each x input, so its size is automatically inferred to twice the size of x. The size of x is itself implicitely bound to be the only dimension declared in the program.

Behind the scene, ScalaCL will create the following OpenCL kernel source code for the previous program :


__kernel function(
__global const float* in,
__global float* out)
{
int dim1 = get_global_id(0);
out[dim1 * 2] = sin(in[dim1]);
out[(dim1 * 2) + 1] = cos(in[dim1]);
}

ScalaCL guesses out that there is one input (read-only) array and one output (read-write) array, and it creates the source code that corresponds to the declared content of the program. The names of the variables are unknown to it though (DSL technical limitation), but sensible names are chosen so that the OpenCL kernels are still readable (“x” became “in”, “sincosx” became “out”) in the debug output. The typical user will never need to look at the generated OpenCL source code anyway…

ScalaCL is still in the very early stages of development but It Already Works (TM) and might soon relieve you from the need to learn too much about OpenCL.

You have a few options to try these examples, in preferred order :

Here are some of the features planned in a near future (besides bugfixes) :

  • Add ImageVar and corresponding functions. Right now, only scalar variables (FloatVar, IntVar…) and array variables (FloatsVar, IntsVar)
  • Add LocalDim and syntax to deal with workgroup size. For now, the workgroup size is always 1
  • Provide automatic support for reductions, through the use of +=, -=, /=, *= operators.

In a soon-to-be-published post I’ll talk about OpenCL4Java performance with some benchmark results for simple parallel operations… Stay tuned :-)

Any feedback is highly welcome, as usual…

This entry was posted in Uncategorized. Bookmark the permalink.

19 Responses to ScalaCL: Reap OpenCL's benefits without learning its syntax (Scala DSL for transparently parallel computations)

  1. Frank says:

    Nice stuff…now I only have to figure out a usecase :)

  2. David Hall says:

    This is wonderful!

    I can’t wait to add this to Scalala and using it in my own code!

    Looking forward to benchmarks

  3. David Hall says:

    (oh, exp and log would be high on wishlist!)

  4. zOlive says:

    @David Oops… That’s now top of my TODO-list (just before ImageVar and JOGL interop), thanks for pointing this out !

  5. zOlive says:

    @David Actually, some of the benchmarks are ready, it’s just that I’d like to be able to run them on some OpenCL-capable GPU hardware (only tested it on MacOS X’s CPU implementation) : OpenCL4JavaBenchmark.
    Maybe someone with such hardware could help… (tests and donations accepted ;-))

  6. Awesome! I’m going to look into how this would work with my vector math library ( http://github.com/Villane/vecmath ) and 2D game engine (not public yet).

  7. zOlive says:

    @David I’ve added log, exp and a few other math functions… (see svn diff here).
    Please let me know if/when you have anything else on your wishlist :-)

  8. Blair says:

    hey, I don’t think the maven instructions work so well.

    com.nativelibs4java
    OpenCL4Java
    1.0-SNAPSHOT
    compile

    points at the wrong place

    com.nativelibs4java.opencl
    OpenCL4Java
    1.0-SNAPSHOT
    compile

    works better (maven can find it!) but fails with
    Project ID: com.nativelibs4java.opencl:OpenCL4Java:jar:1.0-SNAPSHOT

    Reason: Cannot find parent: com.nativelibs4java:nativelibs4java-parent for project: com.nativelibs4java.opencl:OpenCL4Java:jar:1.0-SNAPSHOT for project com.nativelibs4java.opencl:OpenCL4Java:jar:1.0-SNAPSHOT

  9. zOlive says:

    Hi Blair,
    Thanks a lot for reporting these issues !
    I’ve deployed the missing nativelibs4java-parent artifact on the new Maven repository + changed the OpenCL group : the correct dependency section to use is now indeed the one that was described in the Maven page :


    com.nativelibs4java
    OpenCL4Java
    1.0-SNAPSHOT
    compile


    Please tell me if you run into any other issue…
    Cheers

  10. Blair says:

    Weird, it looks like its all there except for its snapshot pom

    http://nativelibs4java.sourceforge.net/maven/com/nativelibs4java/OpenCL4Java/1.0-SNAPSHOT/OpenCL4Java-1.0-SNAPSHOT.pom

    So the actual snapshot is there, but you have to refer to its timestamped version for maven to find it.

    I’m guessing that its parent will have the same problem.

  11. Blair says:

    ok, I have looked at it some more, what we need to use currently to see it is…

    com.nativelibs4java
    OpenCL4Java
    1.0-20090923.235346-1
    compile

    Which isn’t so cool, and more importantly, it still can’t find its parent, since its looking for its parents 1.0-SNAPSHOT which doesn’t exist.

    If the 2 1.0-SNAPSHOT.pom files end up back in the repo, then it should all work nicely.

    Worse case, I can grab the source and build it locally, so it isn’t effecting anything I want to do with it.

    I am giving a Scala presentation, and OpenCL has been talked about in relation to Scala a fair bit, so I’m going to add a bunch of stuff about this project to the presentation next month. So hey, you will have a bunch of crazy New Zealanders looking at (and most likely using) your project :)

    If there is any help I can give with regards to maven (I’m the goto guy for maven around where I work) then give me a bell.

    — Blair

  12. zOlive says:

    Hi Blair,
    The problem might be that I forgot to add the following line to the repo definition :
    false
    (or is it “true” ? I’m still far from being fluent in Maven :-S)
    I’ll try tonight when I come home :-)
    Cheers

  13. zOlive says:

    Ok, so I’ve redone the maven repository with uniqueVersion = false, and I tested it with a dummy Maven project, so this time it should work.
    Thanks for your patience :-)

    Olivier

  14. zOlive says:

    @Blair Hehe, getting invited to New Zealand someday is definitely an excellent long-term goal to keep my motivation up ;-)
    I’d be delighted to help you prepare your presentation in any way… and looking forward to reading your slides if they can be made public afterwards :-)

    Btw, thanks for offering your maven skills ;-)
    I’ve got pending questions about snapshot / release repositories and numbering :
    1) Any reason not to deploy releases and snapshots to the same repo ?
    2) Should version X.Y.Z be considered the final release after X.Y.Z-SNAPSHOT moved a lot, or is X.Y.Z-SNAPSHOT starting after release of X.Y.Z ? (I guess that’s a silly one, but I failed to google it so far…)

    Cheers

  15. Pingback: Ché zOlive » Blog Archive » OpenCL4Java: Build high-performance OpenCL code with Java (and stay calm)

  16. Blair says:

    ok, here is the maven answers….

    1) I’ve been told its a bad idea(tm), but…. I’ve never had problems with it, we did it by accident for quite some time on a project I was involved it (opps!).

    2) releasing 1.1.1-SNAPSHOT will create the 1.1.1 release, and you should start working on 1.1.2-SNAPSHOT at that time. Does that make sense?

    As a note – Once you put in the SVN (or whatever) info into the pom, the release:prepare and release:perform steps for maven is freaking awesome. It handles all of the changing of versions, releases, and tagging of released versions.
    It can however be a bit of a pig to get working, but even if maven did nothing else for you, this would make maven all worth while.

  17. Blair says:

    oh, and I ran my build, and got….

    BUILD SUCCESSFUL

    you are wonderful :) thanks for getting it going!

  18. Pingback: Ché zOlive » Blog Archive » JavaCL 1.0 beta 6 released (kernels caching, includes from classpath, bugfixes…)

Comments are closed.