torutkのブログ

ソフトウェア・エンジニアのブログ

OpenCL Javaバインディング

GPUコンピューティングOpenCLJavaから使うライブラリがありました。幾つか異なるライブラリがあります。

jocl.org

"Java bindings for OpenCL"

ドキュメント・サンプルは充実していそうです。
OpenCL APIC言語インタフェース)を薄くラッピングしたライブラリで、オブジェクト指向APIにはなっていません。定数もそのままの名称で登場します。OpenCL APIC言語で扱っていた人向けかも。

JOCL by JogAmp.org

"Project JOCL"

OpenGLJavaバインディングのひとつJOGLと同じ開発サイトで公開されており、JOGLとのシームレスな統合を唄っています。
ローレベルAPIとハイレベルAPIを提供しているとあります。
Windows版については、ネイティブコード部分のコンパイルMinGWを使用し、Visual C++は基本的にノンサポートです。

javacl

"OpenCL bindings for Java"

  • http://code.google.com/p/javacl/
  • ライセンス:GNU LGPL
  • 最新バージョン:1.0-beta5(2010/7/17)
  • 提供しているJARファイルに、主要OS用ネイティブコード(ライブラリファイル)が含まれている

コーディングイメージ(抜粋)

jocl.org

jocl.orgのプログラミングイメージを次に示します。

cl_platform_id platforms[] = new cl_platform_id[1];
clGetPlatformIDs(platforms.length, platforms, null);
cl_context_properties contextProperties = new cl_context_properties();
contextProperties.addProperty(CL_CONTEXT_PLATFORM, platforms[0]);
cl_context context = clCreateContextFromType(
    contextProperties, CL_DEVICE_TYPE_GPU, null, null, null);
CL.setExceptionsEnabled(true);
long numBytes[] = new long[1];
clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, null, numBytes);
int numDevices = (int) numBytes[0] / Sizeof.cl_device_id;
cl_device_id devices[] = new cl_device_id[numDevices];
clGetContextInfo(context, CL_CONTEXT_DEVICES, numBytes[0],  
    Pointer.to(devices), null);
cl_command_queue commandQueue = 
    clCreateCommandQueue(context, devices[0], 0, null);
cl_mem memObjects[] = new cl_mem[3];
memObjects[0] = ...
memObjects[1] = ...
memObjects[2] = ...
cl_program program = clCreateProgramWithSource(context,
    1, new String[]{ programSource }, null, null);
clBuildProgram(program, 0, null, null, null, null);
cl_kernel kernel = clCreateKernel(program, "sampleKernel", null);
clSetKernelArg(kernel, 0, Sizeof.cl_mem, Pointer.to(memObjects[0]));
clSetKernelArg(kernel, 1, Sizeof.cl_mem, Pointer.to(memObjects[1]));
clSetKernelArg(kernel, 2, Sizeof.cl_mem, Pointer.to(memObjects[2]));
long global_work_size[] = new long[]{n};
long local_work_size[] = new long[]{1};
clEnqueueNDRangeKernel(commandQueue, kernel, 1, null,
            global_work_size, local_work_size, 0, null, null);
clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE, 0,
            n * Sizeof.cl_float, dst, 0, null, null);

見てのとおり、OpenCLC言語APIを見るかのようなコードです。Javaプログラマーとしては、めまいがしてしまいそうです。

JOCL by JogAmp.org

チュートリアルから抜き出したプログラミングイメージ。

CLContext context = CLContext.create();
CLProgram program = context.createProgram(
    HelloJOCL.class.getResourceAsStream("VectorAdd.cl")
).build();
CLBuffer<FloatBuffer> clBufferA = context.createFloatBuffer(globalWorkSize, READ_ONLY);
CLBuffer<FloatBuffer> clBufferB = context.createFloatBuffer(globalWorkSize, READ_ONLY);
CLBuffer<FloatBuffer> clBufferC = context.createFloatBuffer(globalWorkSize, WRITE_ONLY);

fillBuffer(clBufferA.getBuffer(), 12345);
fillBuffer(clBufferB.getBuffer(), 67890);

CLKernel kernel = program.createCLKernel("VectorAdd");
kernel.putArgs(clBufferA, clBufferB, clBufferC).putArg(elementCount);
CLCommandQueue queue = context.getMaxFlopsDevice().createCommandQueue();

queue.putWriteBuffer(clBufferA, false)
             .putWriteBuffer(clBufferB, false)
             .put1DRangeKernel(kernel, 0, globalWorkSize, localWorkSize)
             .putReadBuffer(clBufferC, true);
javacl

javaclのプログラミングイメージを次に示します。

CLContext context = JavaCL.createBestContext();
CLQueue queue = context.createDefaultQueue();
CLKernel kernel = context.createProgram(source).createKernel("addFloats");
CLFloatBuffer aBuf = ...
CLFloatBuffer bBuf = ...
CLFloatBuffer outBuf = ...
kernel.setArgs(aBuf, bBuf, outBuf);
kernel.enqueueNDRange(queue, new int[]{n}, new int[]{1});
queue.finish();

オブジェクト指向っぽく抽象度の高いAPIとなっています。コンテクストとキューを生成し、ソースコード文字列からカーネールを生成してキューに投入という流れです。簡潔に記述できるAPIです。

JogAmp.orgのJOCLビルドは頓挫中

まず、joclのビルドには、glugenが必要。glugenを入手した後、ビルドするのですが、antのビルド設定をいろいろ調整しないとだめなようです。

BUILD FAILED
.略.\build.xml:29: taskdef class com.sun.gluegen.ant.GlueGenTask cannot be found
 using the classloader AntClassLoader[.略.\gluegen\make\lib\antlr.jar]

また、Cのコードをビルドするのもantから行うようですが、コンパイラの指定方法等の調査・設定が必要ですが、未調査。