Skip to content
Olivier Chafik edited this page Nov 10, 2022 · 4 revisions

A few words on the JavaCL Generator Maven plugin

What is it ?

If you're doing OpenCL stuff from Java, you don't want to miss out on the JavaCL Generator : it integrates your OpenCL code to your Java code seamlessly !

The JavaCL Generator is a Maven plugin that automatically parses any OpenCL source file present in src/main/opencl and generates a Java wrapper class that lets you call the kernel very easily from Java.

Simple example

Example OpenCL source file

In the rest of this page, we'll consider the following kernels (from the tutorial), saved in the file src/main/opencl/tutorial/TutorialKernels.cl:

__kernelvoidadd_floats(__globalconstfloat*a, __globalconstfloat*b, __globalfloat*out, intn) {
inti=get_global_id(0);
if (i >= n)
return;
out[i] =a[i] +b[i];
}
__kernelvoidfill_in_values(__globalfloat*a, __globalfloat*b, intn) {
inti=get_global_id(0);
if (i >= n)
return;
a[i] =cos((float)i);
b[i] =sin((float)i);
}

Maven configuration for the JavaCL Generator

This is the configuration needed in your pom.xml to make use of the generator (it adds up to the JavaCL dependency and NativeLibs4Java repository configuration) :

<project>
...
<build>
<plugins>
...
<plugin>
<groupId>com.nativelibs4java</groupId>
<artifactId>javacl-generator</artifactId>
<version>1.0.0-RC1</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Generated code

At each Maven compilation, the JavaCL Generator plugin will automatically generate the following wrapper as target/generated-sources/main/java/tutorial/TutorialKernels.java :

packagecom.mycompany;
importcom.nativelibs4java.opencl.CLAbstractUserProgram;
importcom.nativelibs4java.opencl.CLBuffer;
importcom.nativelibs4java.opencl.CLBuildException;
importcom.nativelibs4java.opencl.CLContext;
importcom.nativelibs4java.opencl.CLEvent;
importcom.nativelibs4java.opencl.CLKernel;
importcom.nativelibs4java.opencl.CLProgram;
importcom.nativelibs4java.opencl.CLQueue;
importjava.io.IOException;
/// Wrapper around the OpenCL program TutorialKernelspublicclassTutorialKernelsextendsCLAbstractUserProgram {
publicTutorialKernels(CLContextcontext) throwsIOException {
super(context, readRawSourceForClass(TutorialKernels.class));
}
publicTutorialKernels(CLProgramprogram) throwsIOException {
super(program, readRawSourceForClass(TutorialKernels.class));
}
CLKerneladd_floats_kernel;
publicsynchronizedCLEventadd_floats(CLQueuecommandQueue, CLBuffer<Float > a, CLBuffer<Float > b, CLBuffer<Float > out, intn, intglobalWorkSizes[], intlocalWorkSizes[], CLEvent... eventsToWaitFor) throwsCLBuildException {
if (add_floats_kernel == null) add_floats_kernel = createKernel("add_floats");
add_floats_kernel.setArgs(a, b, out, n);
returnadd_floats_kernel.enqueueNDRange(commandQueue, globalWorkSizes, localWorkSizes, eventsToWaitFor);
}
CLKernelfill_in_values_kernel;
publicsynchronizedCLEventfill_in_values(CLQueuecommandQueue, CLBuffer<Float > a, CLBuffer<Float > b, intn, intglobalWorkSizes[], intlocalWorkSizes[], CLEvent... eventsToWaitFor) throwsCLBuildException {
if (fill_in_values_kernel == null) fill_in_values_kernel = createKernel("fill_in_values");
fill_in_values_kernel.setArgs(a, b, n);
returnfill_in_values_kernel.enqueueNDRange(commandQueue, globalWorkSizes, localWorkSizes, eventsToWaitFor);
}
}

Why using the Generator ?

Type-safety of Java-to-OpenCL-kernels calls

With the generator, you get compile-time checks of the argument types of your kernels, with complete synchronization with your OpenCL sources.

The alternative is to call CLKernel.setArgs(Object...) on your kernels prior to enqueuing them for execution, and it's dangerous for you might not be using the correct number of arguments or the correct argument types : your program will then crash at runtime or just be buggy and make you cry.

Remember why you're using Java/Scala instead of Php/Ruby ? Get the free compile-time checks for OpenCL now ;-)

Less boilerplate code

Compare this (with the generator) :

TutorialKernelskernels = newTutorialKernels(context);
int[] globalSizes = newint[] { n };
CLEventfillEvt = kernels.fill_in_values(queue, a, b, n, globalSizes, null);
CLEventaddEvt = kernels.add_floats(queue, a, b, out, n, globalSizes, null, fillEvt);

To that (without the generator) :

// Read the program sources and compile them :Stringsrc = IOUtils.readText(JavaCLTutorial1.class.getResource("TutorialKernels.cl"));
CLProgramprogram = context.createProgram(src);
CLKernelfillValuesKernel = program.createKernel("fill_in_values");
CLKerneladdFloatsKernel = program.createKernel("add_floats");
// Get and call the kernel :int[] globalSizes = newint[] { n };
fillValuesKernel.setArgs(a, b, n);
CLEventfillEvt = fillValuesKernel.enqueueNDRange(queue, globalSizes);
addFloatsKernel.setArgs(a, b, out, n);
CLEventaddEvt = addFloatsKernel.enqueueNDRange(queue, globalSizes, fillEvt);

How does it work ?

Well, it's just a derivative of [JNAerator] (which is written by the same https://ochafik.com/ original author as JavaCL ;-))

Legal details (no need to read that)

The generated Java sources (OpenCL wrappers) are explicitly left free of any copyright/licensing bullshit from nativelibs4java, so you can do whatever you want with them (they mainly reflect your OpenCL code anyway).

The generator itself, however, is currently licensed under the LGPL, as it is a derivative of [JNAerator] (it is planned to switch it to the BSD license, CreditsAndLicense as JavaCL itself, but JNAerator needs to decouple from JNA first so it may take a while...).

Clone this wiki locally