diff options
author | Michael Bien <[email protected]> | 2009-10-23 00:21:58 +0200 |
---|---|---|
committer | Michael Bien <[email protected]> | 2009-10-23 00:21:58 +0200 |
commit | 054e5005d1429ba6ea4f9283eee2988ff54d1abb (patch) | |
tree | 163f7124f6dba109de965f3382f8b2613cf2068c | |
parent | 503845224a820c0b9ce9204aa6215519f6b93c36 (diff) |
utility methods and refactoring.
-rw-r--r-- | resources/cl-if.cfg | 6 | ||||
-rw-r--r-- | resources/cl-impl.cfg | 2 | ||||
-rw-r--r-- | resources/clImplCustomCode.c | 34 | ||||
-rw-r--r-- | resources/clImplCustomCode.java | 18 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLBuffer.java | 127 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLCommandQueue.java | 38 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLContext.java | 98 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLDevice.java | 150 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLKernel.java | 3 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLProgram.java | 257 | ||||
-rw-r--r-- | test/com/mbien/opencl/HighLevelBindingTest.java | 16 | ||||
-rw-r--r-- | test/com/mbien/opencl/LowLevelBindingTest.java | 2 |
12 files changed, 442 insertions, 309 deletions
diff --git a/resources/cl-if.cfg b/resources/cl-if.cfg index 4d7d80f1..8a4d62d8 100644 --- a/resources/cl-if.cfg +++ b/resources/cl-if.cfg @@ -7,7 +7,7 @@ Import java.nio.IntBuffer ClassJavadoc CL /** ClassJavadoc CL * Java bindings to OpenCL, the Open Computing Language. -ClassJavadoc CL * @autor Michael Bien +ClassJavadoc CL * @author Michael Bien ClassJavadoc CL */ JavaClass CL @@ -18,12 +18,12 @@ Ignore CL_GL_.*|cl.*GL.* Ignore clCreateContext CustomJavaCode CL CustomJavaCode CL /** Interface to C language function: <br> <code> cl_context clCreateContext(intptr_t * , uint32_t, cl_device_id * , void (*pfn_notify)(const char *, const void *, size_t, void *), void *, int32_t * ); </code> */ -CustomJavaCode CL public long clCreateContext(IntBuffer properties, int properties_offset, long[] devices, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int errcode_offset); +CustomJavaCode CL public long clCreateContext(IntBuffer properties, long[] devices, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret); Ignore clCreateContextFromType CustomJavaCode CL CustomJavaCode CL /** Interface to C language function: <br> <code> cl_context clCreateContextFromType(cl_context_properties *properties, cl_device_type device_type, void (*pfn_notify)(const char *errinfo, const void *private_info, size_t cb, void *user_data), void *user_data, cl_int *errcode_ret) ; </code> */ -CustomJavaCode CL public long clCreateContextFromType(IntBuffer properties, int properties_offset, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int errcode_offset); +CustomJavaCode CL public long clCreateContextFromType(IntBuffer properties, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret); Ignore clBuildProgram CustomJavaCode CL diff --git a/resources/cl-impl.cfg b/resources/cl-impl.cfg index 58d06be2..cee848c8 100644 --- a/resources/cl-impl.cfg +++ b/resources/cl-impl.cfg @@ -9,7 +9,7 @@ Import java.nio.Buffer ClassJavadoc CLImpl /** ClassJavadoc CLImpl * Java bindings to OpenCL, the Open Computing Language. -ClassJavadoc CLImpl * @autor Michael Bien +ClassJavadoc CLImpl * @author Michael Bien ClassJavadoc CLImpl */ ImplJavaClass CLImpl diff --git a/resources/clImplCustomCode.c b/resources/clImplCustomCode.c index 41e9f159..a35328dc 100644 --- a/resources/clImplCustomCode.c +++ b/resources/clImplCustomCode.c @@ -24,9 +24,8 @@ void createContextCallback(const char * c, const void * v, size_t s, void * o) { * void * user_data , * cl_int * errcode_ret ); */ -//__Ljava_lang_Object_2IJLjava_lang_Object_2Ljava_lang_Object_2Ljava_lang_Object_2I JNIEXPORT jlong JNICALL -Java_com_mbien_opencl_impl_CLImpl_clCreateContextFromType0(JNIEnv *env, jobject _unused, +Java_com_mbien_opencl_impl_CLImpl_clCreateContextFromType1(JNIEnv *env, jobject _unused, jobject props, jint props_byte_offset, jlong device_type, jobject cb, jobject data, jobject errcode, jint errcode_byte_offset) { intptr_t * _props_ptr = NULL; @@ -34,26 +33,21 @@ Java_com_mbien_opencl_impl_CLImpl_clCreateContextFromType0(JNIEnv *env, jobject cl_context _ctx; if (props != NULL) { - _props_ptr = (intptr_t *) (((char*) (*env)->GetDirectBufferAddress(env, props)) + props_byte_offset); + _props_ptr = (void *) (((char*) (*env)->GetPrimitiveArrayCritical(env, props, NULL)) + props_byte_offset); } if (errcode != NULL) { - _errcode_ptr = (int32_t *) (((char*) (*env)->GetDirectBufferAddress(env, errcode)) + errcode_byte_offset); + _errcode_ptr = (void *) (((char*) (*env)->GetPrimitiveArrayCritical(env, errcode, NULL)) + errcode_byte_offset); } //TODO callback; payload - _ctx = clCreateContextFromType((intptr_t *) _props_ptr, (uint64_t) device_type, NULL, NULL, (int32_t *) _errcode_ptr); + _ctx = clCreateContextFromType((cl_context_properties *) _props_ptr, (uint64_t) device_type, NULL, NULL, (int32_t *) _errcode_ptr); -/* - printf(" - - - - test - - - - \n"); - cl_uint err; - size_t deviceListSize; - - // get the list of GPU devices associated with context - err = clGetContextInfo(_ctx, CL_CONTEXT_DEVICES, 0, NULL, &deviceListSize); checkStatus("getContextInfo1", err); - cl_uint count = (cl_uint)deviceListSize / sizeof(cl_device_id); - printf("devices: %d \n", count); - printf(" - - - - test end - - - - \n"); -*/ + if (errcode != NULL) { + (*env)->ReleasePrimitiveArrayCritical(env, errcode, _errcode_ptr, 0); + } + if (props != NULL) { + (*env)->ReleasePrimitiveArrayCritical(env, props, _props_ptr, 0); + } return (jlong)_ctx; } @@ -111,14 +105,6 @@ Java_com_mbien_opencl_impl_CLImpl_clBuildProgram0(JNIEnv *env, jobject _unused, _deviceListPtr = (void *) (((char*) (*env)->GetPrimitiveArrayCritical(env, deviceList, NULL)) + offset); } -/* - printf("---------------------------------------------------------------------------\n"); - printf("deviceList: %d\n", _deviceListPtr); - printf("_strchars_options: %d\n", _strchars_options); - printf("deviceCount: %d\n", deviceCount); - printf("---------------------------------------------------------------------------\n"); -*/ - // TODO payload, callback... _res = clBuildProgram((cl_program)program, (cl_uint)deviceCount, _deviceListPtr, _strchars_options, NULL, NULL); diff --git a/resources/clImplCustomCode.java b/resources/clImplCustomCode.java index 3c5e1f07..0d25ddb6 100644 --- a/resources/clImplCustomCode.java +++ b/resources/clImplCustomCode.java @@ -1,23 +1,25 @@ - public long clCreateContext(IntBuffer properties, int offset1, long[] devices, CreateContextCallback cb, Object userData, IntBuffer errcode_ret, int offset2) { + public long clCreateContext(IntBuffer properties, long[] devices, CreateContextCallback cb, Object userData, IntBuffer errcode_ret) { throw new RuntimeException("not yet implemented, use clCreateContextFromType instead"); // return this.clCreateContext0(properties, offset1, devices, cb, null, errcode_ret, offset2); } - private native long clCreateContext0(IntBuffer cl_context_properties, int size, long[] devices, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int size2); + private native long clCreateContext0(Object cl_context_properties, int props_offset, long[] devices, CreateContextCallback pfn_notify, Object userData, Object errcode_ret, int err_offset); - - public long clCreateContextFromType(IntBuffer properties, int offset1, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int offset2) { + + public long clCreateContextFromType(IntBuffer properties, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret) { if(pfn_notify != null) throw new RuntimeException("asynchronous execution with callback is not yet implemented, pass null through this method to block until complete."); if(userData != null) - System.out.println("WARNING: userData not yet implemented... ignoring"); + System.err.println("WARNING: userData not yet implemented... ignoring"); - return this.clCreateContextFromType0(properties, offset1, device_type, pfn_notify, null, errcode_ret, offset2); + return this.clCreateContextFromType1( + BufferFactory.getArray(properties), BufferFactory.getIndirectBufferByteOffset(properties), device_type, pfn_notify, null, + BufferFactory.getArray(errcode_ret), BufferFactory.getIndirectBufferByteOffset(errcode_ret) ); } - private native long clCreateContextFromType0(IntBuffer properties, int size, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int size2); + private native long clCreateContextFromType1(Object properties, int props_offset, long device_type, CreateContextCallback pfn_notify, Object userData, Object errcode_ret, int err_offset); /** Interface to C language function: <br> <code> int32_t clBuildProgram(cl_program, uint32_t, cl_device_id * , const char * , void * ); </code> */ @@ -27,7 +29,7 @@ throw new RuntimeException("asynchronous execution with callback is not yet implemented, pass null through this method to block until complete."); if(userData != null) - System.out.println("WARNING: userData not yet implemented... ignoring"); + System.err.println("WARNING: userData not yet implemented... ignoring"); int listLength = 0; if(deviceList != null) diff --git a/src/com/mbien/opencl/CLBuffer.java b/src/com/mbien/opencl/CLBuffer.java index 185389c3..7c195ba7 100644 --- a/src/com/mbien/opencl/CLBuffer.java +++ b/src/com/mbien/opencl/CLBuffer.java @@ -9,7 +9,65 @@ import static com.mbien.opencl.CLException.*; */ public class CLBuffer { - public enum MEM { + public final ByteBuffer buffer; + public final long ID; + + private final CLContext context; + private final CL cl; + + CLBuffer(CLContext context, ByteBuffer directBuffer, int flags) { + + if(!directBuffer.isDirect()) + throw new IllegalArgumentException("buffer is not a direct buffer"); + + this.buffer = directBuffer; + this.context = context; + this.cl = context.cl; + + int[] intArray = new int[1]; + + this.ID = cl.clCreateBuffer(context.ID, flags, directBuffer.capacity(), null, intArray, 0); + + checkForError(intArray[0], "can not create cl buffer"); + + } + + public void release() { + int ret = cl.clReleaseMemObject(ID); + context.onBufferReleased(this); + checkForError(ret, "can not release mem object"); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CLBuffer other = (CLBuffer) obj; + if (this.buffer != other.buffer && (this.buffer == null || !this.buffer.equals(other.buffer))) { + return false; + } + if (this.context.ID != other.context.ID) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 29 * hash + (this.buffer != null ? this.buffer.hashCode() : 0); + hash = 29 * hash + (int) (this.context.ID ^ (this.context.ID >>> 32)); + return hash; + } + + /** + * Memory settings for configuring CLBuffers. + */ + public enum Mem { /** * This flag specifies that the memory object will be read and @@ -56,11 +114,11 @@ public class CLBuffer { */ public final int CL_FLAG; - private MEM(int CL_TYPE) { - this.CL_FLAG = CL_TYPE; + private Mem(int CL_FLAG) { + this.CL_FLAG = CL_FLAG; } - public static MEM valueOf(int bufferFlag) { + public static Mem valueOf(int bufferFlag) { switch(bufferFlag) { case(CL.CL_MEM_READ_WRITE): return READ_WRITE; @@ -76,7 +134,7 @@ public class CLBuffer { return null; } - static int flagsToInt(MEM[] flags) { + static int flagsToInt(Mem[] flags) { int clFlags = 0; if(flags != null) { for (int i = 0; i < flags.length; i++) { @@ -90,63 +148,4 @@ public class CLBuffer { } - - public final ByteBuffer buffer; - public final long ID; - - private final CLContext context; - private final CL cl; - - CLBuffer(CLContext context, ByteBuffer directBuffer, int flags) { - - if(!directBuffer.isDirect()) - throw new IllegalArgumentException("buffer is not a direct buffer"); - - this.buffer = directBuffer; - this.context = context; - this.cl = context.cl; - - int[] intArray = new int[1]; - - this.ID = cl.clCreateBuffer(context.ID, flags, directBuffer.capacity(), null, intArray, 0); - - checkForError(intArray[0], "can not create cl buffer"); - - } - - public void release() { - int ret = cl.clReleaseMemObject(ID); - context.onBufferReleased(this); - checkForError(ret, "can not release mem object"); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final CLBuffer other = (CLBuffer) obj; - if (this.buffer != other.buffer && (this.buffer == null || !this.buffer.equals(other.buffer))) { - return false; - } - if (this.context.ID != other.context.ID) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 29 * hash + (this.buffer != null ? this.buffer.hashCode() : 0); - hash = 29 * hash + (int) (this.context.ID ^ (this.context.ID >>> 32)); - return hash; - } - - - - } diff --git a/src/com/mbien/opencl/CLCommandQueue.java b/src/com/mbien/opencl/CLCommandQueue.java index 5abc5cd5..00e1d6b0 100644 --- a/src/com/mbien/opencl/CLCommandQueue.java +++ b/src/com/mbien/opencl/CLCommandQueue.java @@ -3,7 +3,12 @@ package com.mbien.opencl; import static com.mbien.opencl.CLException.*; /** - * + * The command-queue can be used to queue a set of operations in order. Having multiple + * command-queues allows applications to queue multiple independent commands without + * requiring synchronization. Note that this should work as long as these objects are + * not being shared.<b/> + * Sharing of objects across multiple command-queues will require the application to + * perform appropriate synchronization. * @author Michael Bien */ public class CLCommandQueue { @@ -190,5 +195,36 @@ public class CLCommandQueue { return hash; } + /** + * Enumeration for the command-queue settings. + */ + public enum Mode { + /** + * CL_DEVICE_TYPE_CPU + */ + OUT_OF_ORDER_EXEC_MODE(CL.CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE), + /** + * CL_DEVICE_TYPE_GPU + */ + PROFILING_MODE(CL.CL_QUEUE_PROFILING_ENABLE); + + /** + * Value of wrapped OpenCL device type. + */ + public final int CL_QUEUE_MODE; + + private Mode(int CL_VALUE) { + this.CL_QUEUE_MODE = CL_VALUE; + } + public static Mode valueOf(int queueMode) { + switch(queueMode) { + case(CL.CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE): + return OUT_OF_ORDER_EXEC_MODE; + case(CL.CL_QUEUE_PROFILING_ENABLE): + return PROFILING_MODE; + } + return null; + } + } } diff --git a/src/com/mbien/opencl/CLContext.java b/src/com/mbien/opencl/CLContext.java index a82092bb..81ac58f0 100644 --- a/src/com/mbien/opencl/CLContext.java +++ b/src/com/mbien/opencl/CLContext.java @@ -1,6 +1,6 @@ package com.mbien.opencl; -import com.mbien.opencl.CLBuffer.MEM; +import com.mbien.opencl.CLBuffer.Mem; import com.sun.gluegen.runtime.BufferFactory; import com.sun.gluegen.runtime.CPU; import java.io.BufferedReader; @@ -19,7 +19,9 @@ import java.util.Map; import static com.mbien.opencl.CLException.*; /** - * + * CLContext is responsible for managing objects such as command-queues, memory, + * program and kernel objects and for executing kernels on one or more devices + * specified in the context. * @author Michael Bien */ public final class CLContext { @@ -42,30 +44,71 @@ public final class CLContext { this.queuesMap = new HashMap<CLDevice, List<CLCommandQueue>>(); } + private final void initDevices() { + + if (devices == null) { + + int sizeofDeviceID = CPU.is32Bit() ? 4 : 8; + long[] longBuffer = new long[1]; + + int ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, 0, null, longBuffer, 0); + checkForError(ret, "can not enumerate devices"); + + ByteBuffer deviceIDs = ByteBuffer.allocate((int) longBuffer[0]).order(ByteOrder.nativeOrder()); + ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, deviceIDs.capacity(), deviceIDs, null, 0); + checkForError(ret, "can not enumerate devices"); + + devices = new CLDevice[deviceIDs.capacity() / sizeofDeviceID]; + for (int i = 0; i < devices.length; i++) { + devices[i] = new CLDevice(this, CPU.is32Bit() ? deviceIDs.getInt() : deviceIDs.getLong()); + } + } + } + /** - * Creates a default context on all available devices. + * Creates a default context on all available devices (CL_DEVICE_TYPE_ALL). + * The platform to be used is implementation dependent. */ public static final CLContext create() { - return createContext(CL.CL_DEVICE_TYPE_ALL); + return createContext(null, CL.CL_DEVICE_TYPE_ALL); } /** * Creates a default context on the specified device types. + * The platform to be used is implementation dependent. */ public static final CLContext create(CLDevice.Type... deviceTypes) { + return create(null, deviceTypes); + } - int type = deviceTypes[0].CL_TYPE; - for (int i = 1; i < deviceTypes.length; i++) { - type |= deviceTypes[i].CL_TYPE; + // TODO check if driver bug, otherwise find the reason why this is not working (INVALID_VALUE with NV driver) + /** + * Creates a default context on the specified platform and with the specified + * device types. + */ + private static final CLContext create(CLPlatform platform, CLDevice.Type... deviceTypes) { + + int type = 0; + if(deviceTypes != null) { + for (int i = 0; i < deviceTypes.length; i++) { + type |= deviceTypes[i].CL_TYPE; + } } - return createContext(type); + IntBuffer properties = null; + if(platform != null) { + properties = IntBuffer.allocate(3); + properties.put(CL.CL_CONTEXT_PLATFORM).put((int)platform.ID).put(0); // TODO check if this has to be int or long + properties.rewind(); + } + + return createContext(properties, type); } - private static final CLContext createContext(long deviceType) { + private static final CLContext createContext(IntBuffer properties, long deviceType) { IntBuffer status = IntBuffer.allocate(1); - long context = CLPlatform.getLowLevelBinding().clCreateContextFromType(null, 0, deviceType, null, null, status, 0); + long context = CLPlatform.getLowLevelBinding().clCreateContextFromType(properties, deviceType, null, null, status); checkForError(status.get(), "can not create CL context"); @@ -104,14 +147,14 @@ public final class CLContext { /** * Creates a CLBuffer with the specified flags. No flags creates a MEM.READ_WRITE buffer. */ - public CLBuffer createBuffer(ByteBuffer directBuffer, MEM... flags) { - return createBuffer(directBuffer, MEM.flagsToInt(flags)); + public CLBuffer createBuffer(ByteBuffer directBuffer, Mem... flags) { + return createBuffer(directBuffer, Mem.flagsToInt(flags)); } /** * Creates a CLBuffer with the specified flags. No flags creates a MEM.READ_WRITE buffer. */ - public CLBuffer createBuffer(int size, MEM... flags) { - return createBuffer(size, MEM.flagsToInt(flags)); + public CLBuffer createBuffer(int size, Mem... flags) { + return createBuffer(size, Mem.flagsToInt(flags)); } public CLBuffer createBuffer(int size, int flags) { @@ -187,6 +230,8 @@ public final class CLContext { /** * Gets the device with maximal FLOPS from this context. + * The device speed is estimated by calulating the product of + * MAX_COMPUTE_UNITS and MAX_CLOCK_FREQUENCY. */ public CLDevice getMaxFlopsDevice() { @@ -215,29 +260,7 @@ public final class CLContext { * Returns all devices associated with this CLContext. */ public CLDevice[] getCLDevices() { - - if(devices == null) { - - int sizeofDeviceID = CPU.is32Bit()?4:8; - - long[] longBuffer = new long[1]; - - int ret; - ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, 0, null, longBuffer, 0); - checkForError(ret, "can not enumerate devices"); - - ByteBuffer deviceIDs = ByteBuffer.allocate((int)longBuffer[0]).order(ByteOrder.nativeOrder()); - - ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, deviceIDs.capacity(), deviceIDs, null, 0); - checkForError(ret, "can not enumerate devices"); - - devices = new CLDevice[deviceIDs.capacity()/sizeofDeviceID]; - for (int i = 0; i < devices.length; i++) { - devices[i] = new CLDevice(this, - CPU.is32Bit()?deviceIDs.getInt():deviceIDs.getLong()); - } - } - + initDevices(); return devices; } @@ -279,5 +302,4 @@ public final class CLContext { return hash; } - } diff --git a/src/com/mbien/opencl/CLDevice.java b/src/com/mbien/opencl/CLDevice.java index 87616516..0ad8f0e9 100644 --- a/src/com/mbien/opencl/CLDevice.java +++ b/src/com/mbien/opencl/CLDevice.java @@ -15,51 +15,6 @@ import static com.mbien.opencl.CLException.*; */ public final class CLDevice { - /** - * Enumeration for the type of a device. - */ - public enum Type { - /** - * CL_DEVICE_TYPE_CPU - */ - CPU(CL.CL_DEVICE_TYPE_CPU), - /** - * CL_DEVICE_TYPE_GPU - */ - GPU(CL.CL_DEVICE_TYPE_GPU), - /** - * CL_DEVICE_TYPE_ACCELERATOR - */ - ACCELERATOR(CL.CL_DEVICE_TYPE_ACCELERATOR), - /** - * CL_DEVICE_TYPE_DEFAULT - */ - DEFAULT(CL.CL_DEVICE_TYPE_DEFAULT); - - /** - * Value of wrapped OpenCL device type. - */ - public final int CL_TYPE; - - private Type(int CL_TYPE) { - this.CL_TYPE = CL_TYPE; - } - - public static Type valueOf(int clDeviceType) { - switch(clDeviceType) { - case(CL.CL_DEVICE_TYPE_DEFAULT): - return DEFAULT; - case(CL.CL_DEVICE_TYPE_CPU): - return CPU; - case(CL.CL_DEVICE_TYPE_GPU): - return GPU; - case(CL.CL_DEVICE_TYPE_ACCELERATOR): - return ACCELERATOR; - } - return null; - } - } - private final CL cl; private CLContext context; @@ -82,6 +37,20 @@ public final class CLDevice { public CLCommandQueue createCommandQueue() { return createCommandQueue(0); } + + public CLCommandQueue createCommandQueue(CLCommandQueue.Mode property) { + return createCommandQueue(property.CL_QUEUE_MODE); + } + + public CLCommandQueue createCommandQueue(CLCommandQueue.Mode... properties) { + int flags = 0; + if(properties != null) { + for (int i = 0; i < properties.length; i++) { + flags |= properties[i].CL_QUEUE_MODE; + } + } + return createCommandQueue(flags); + } public CLCommandQueue createCommandQueue(long properties) { if(context == null) @@ -123,41 +92,77 @@ public final class CLDevice { } /** - * Returns the maximal number of compute units. + * Returns the number of parallel compute cores on the OpenCL device. + * The minimum value is 1. */ public int getMaxComputeUnits() { return (int) getInfoLong(CL.CL_DEVICE_MAX_COMPUTE_UNITS); } /** - * Returns the maximal work group size. + * Returns the maximum number of work-items in a work-group executing + * a kernel using the data parallel execution model. + * The minimum value is 1. */ public int getMaxWorkGroupSize() { return (int) getInfoLong(CL.CL_DEVICE_MAX_WORK_GROUP_SIZE); } /** - * Returns the max clock frequency in Hz. + * Returns the maximum configured clock frequency of the device in MHz. */ public int getMaxClockFrequency() { return (int) (getInfoLong(CL.CL_DEVICE_MAX_CLOCK_FREQUENCY)); } /** - * Returns the global memory size in Bytes. + * Returns the maximum dimensions that specify the global and local work-item + * IDs used by the data parallel execution model. + * The minimum value is 3. + */ + public int getMaxWorkItemDimensions() { + return (int) getInfoLong(CL.CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS); + } + + /** + * Returns the global memory size in bytes. */ public long getGlobalMemSize() { return getInfoLong(CL.CL_DEVICE_GLOBAL_MEM_SIZE); } /** - * Returns the local memory size in Bytes. + * Returns the local memory size in bytes. */ public long getLocalMemSize() { return getInfoLong(CL.CL_DEVICE_LOCAL_MEM_SIZE); } /** + * Returns the max size in bytes of a constant buffer allocation. + * The minimum value is 64 KB. + */ + public long getMaxConstantBufferSize() { + return getInfoLong(CL.CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE); + } + + /** + * Returns true if this device is available. + */ + public boolean isAvailable() { + return getInfoLong(CL.CL_DEVICE_AVAILABLE) == CL.CL_TRUE; + } + + /** + * Returns false if the implementation does not have a compiler available to + * compile the program source. Is true if the compiler is available. + * This can be false for the OpenCL ES profile only. + */ + public boolean isCompilerAvailable() { + return getInfoLong(CL.CL_DEVICE_COMPILER_AVAILABLE) == CL.CL_TRUE; + } + + /** * Returns all device extension names as unmodifiable Set. */ public Set<String> getExtensions() { @@ -233,4 +238,49 @@ public final class CLDevice { return hash; } + /** + * Enumeration for the type of a device. + */ + public enum Type { + /** + * CL_DEVICE_TYPE_CPU + */ + CPU(CL.CL_DEVICE_TYPE_CPU), + /** + * CL_DEVICE_TYPE_GPU + */ + GPU(CL.CL_DEVICE_TYPE_GPU), + /** + * CL_DEVICE_TYPE_ACCELERATOR + */ + ACCELERATOR(CL.CL_DEVICE_TYPE_ACCELERATOR), + /** + * CL_DEVICE_TYPE_DEFAULT + */ + DEFAULT(CL.CL_DEVICE_TYPE_DEFAULT); + + /** + * Value of wrapped OpenCL device type. + */ + public final int CL_TYPE; + + private Type(int CL_TYPE) { + this.CL_TYPE = CL_TYPE; + } + + public static Type valueOf(int clDeviceType) { + switch(clDeviceType) { + case(CL.CL_DEVICE_TYPE_DEFAULT): + return DEFAULT; + case(CL.CL_DEVICE_TYPE_CPU): + return CPU; + case(CL.CL_DEVICE_TYPE_GPU): + return GPU; + case(CL.CL_DEVICE_TYPE_ACCELERATOR): + return ACCELERATOR; + } + return null; + } + } + } diff --git a/src/com/mbien/opencl/CLKernel.java b/src/com/mbien/opencl/CLKernel.java index 838f5969..3388251b 100644 --- a/src/com/mbien/opencl/CLKernel.java +++ b/src/com/mbien/opencl/CLKernel.java @@ -76,6 +76,9 @@ public class CLKernel { return BufferFactory.newDirectByteBuffer(8).putLong(value).rewind(); } + /** + * Releases all resources of this kernel from its context. + */ public void release() { int ret = cl.clReleaseKernel(ID); program.onKernelReleased(this); diff --git a/src/com/mbien/opencl/CLProgram.java b/src/com/mbien/opencl/CLProgram.java index 70656373..ff2919e8 100644 --- a/src/com/mbien/opencl/CLProgram.java +++ b/src/com/mbien/opencl/CLProgram.java @@ -21,39 +21,6 @@ public class CLProgram { private final Map<String, CLKernel> kernels; - public enum Status { - - BUILD_SUCCESS(CL.CL_BUILD_SUCCESS), - BUILD_NONE(CL.CL_BUILD_NONE), - BUILD_IN_PROGRESS(CL.CL_BUILD_IN_PROGRESS), - BUILD_ERROR(CL.CL_BUILD_ERROR); - - /** - * Value of wrapped OpenCL device type. - */ - public final int CL_BUILD_STATUS; - - private Status(int CL_BUILD_STATUS) { - this.CL_BUILD_STATUS = CL_BUILD_STATUS; - } - - public static Status valueOf(int clBuildStatus) { - switch(clBuildStatus) { - case(CL.CL_BUILD_SUCCESS): - return BUILD_SUCCESS; - case(CL.CL_BUILD_NONE): - return BUILD_NONE; - case(CL.CL_BUILD_IN_PROGRESS): - return BUILD_IN_PROGRESS; - case(CL.CL_BUILD_ERROR): - return BUILD_ERROR; -// is this a standard state? -// case (CL.CL_BUILD_PROGRAM_FAILURE): -// return BUILD_PROGRAM_FAILURE; - } - return null; - } - } CLProgram(CLContext context, String src, long contextID) { @@ -68,6 +35,76 @@ public class CLProgram { checkForError(intArray[0], "can not create program with source"); } + private final void initKernels() { + + if(kernels.isEmpty()) { + int[] intArray = new int[1]; + int ret = cl.clCreateKernelsInProgram(ID, 0, null, 0, intArray, 0); + checkForError(ret, "can not create kernels for program"); + + long[] kernelIDs = new long[intArray[0]]; + ret = cl.clCreateKernelsInProgram(ID, kernelIDs.length, kernelIDs, 0, null, 0); + checkForError(ret, "can not create kernels for program"); + + for (int i = 0; i < intArray[0]; i++) { + CLKernel kernel = new CLKernel(this, kernelIDs[i]); + kernels.put(kernel.name, kernel); + } + } + } + + // TODO serialization, program build options + + private final String getBuildInfoString(long device, int flag) { + + long[] longArray = new long[1]; + + int ret = cl.clGetProgramBuildInfo(ID, device, flag, 0, null, longArray, 0); + checkForError(ret, "on clGetProgramBuildInfo"); + + ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); + + ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); + checkForError(ret, "on clGetProgramBuildInfo"); + + return new String(bb.array(), 0, (int)longArray[0]); + } + + private final String getProgramInfoString(int flag) { + + long[] longArray = new long[1]; + + int ret = cl.clGetProgramInfo(ID, flag, 0, null, longArray, 0); + checkForError(ret, "on clGetProgramInfo"); + + ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); + + ret = cl.clGetProgramInfo(ID, flag, bb.capacity(), bb, null, 0); + checkForError(ret, "on clGetProgramInfo"); + + return new String(bb.array(), 0, (int)longArray[0]); + } + +// private int getProgramInfoInt(int flag) { +// +// ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); +// +// int ret = cl.clGetProgramInfo(programID, flag, bb.capacity(), bb, null, 0); +// checkForError(ret, ""); +// +// return bb.getInt(); +// } + + private int getBuildInfoInt(long device, int flag) { + + ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); + + int ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); + checkForError(ret, "error on clGetProgramBuildInfo"); + + return bb.getInt(); + } + /** * Builds this program for all devices associated with the context and implementation specific build options. @@ -79,6 +116,15 @@ public class CLProgram { } /** + * Builds this program for all devices associated with the context using the specified build options. + * @return this + */ + public CLProgram build(String options) { + build(null, options); + return this; + } + + /** * Builds this program for the given devices and with the specified build options. * @return this * @param devices A list of devices this program should be build on or null for all devices of its context. @@ -100,30 +146,6 @@ public class CLProgram { return this; } - /** - * Returns all kernels of this program in a unmodifiable view of a map with the kernel function names as keys. - */ - public Map<String, CLKernel> getCLKernels() { - - if(kernels.isEmpty()) { - - int[] intArray = new int[1]; - int ret = cl.clCreateKernelsInProgram(ID, 0, null, 0, intArray, 0); - checkForError(ret, "can not create kernels for program"); - - long[] kernelIDs = new long[intArray[0]]; - ret = cl.clCreateKernelsInProgram(ID, kernelIDs.length, kernelIDs, 0, null, 0); - checkForError(ret, "can not create kernels for program"); - - for (int i = 0; i < intArray[0]; i++) { - CLKernel kernel = new CLKernel(this, kernelIDs[i]); - kernels.put(kernel.name, kernel); - } - } - - return Collections.unmodifiableMap(kernels); - } - void onKernelReleased(CLKernel kernel) { this.kernels.remove(kernel.name); } @@ -147,6 +169,24 @@ public class CLProgram { } /** + * Returns the kernel with the specified name or null if not found. + */ + public CLKernel getCLKernel(String kernelName) { + initKernels(); + return kernels.get(kernelName); + } + + + /** + * Returns all kernels of this program in a unmodifiable view of a map + * with the kernel function names as keys. + */ + public Map<String, CLKernel> getCLKernels() { + initKernels(); + return Collections.unmodifiableMap(kernels); + } + + /** * Returns all devices associated with this program. */ public CLDevice[] getCLDevices() { @@ -169,22 +209,34 @@ public class CLProgram { } + /** + * Returns the build log for this program. The contents of the log are + * implementation dependent log can be an empty String. + */ public String getBuildLog(CLDevice device) { return getBuildInfoString(device.ID, CL.CL_PROGRAM_BUILD_LOG); } + /** + * Returns the build status enum for this program on the specified device. + */ public Status getBuildStatus(CLDevice device) { int clStatus = getBuildInfoInt(device.ID, CL.CL_PROGRAM_BUILD_STATUS); return Status.valueOf(clStatus); } /** - * Returns the source code of this program. Note: sources are not cached, each call of this method calls into OpenCL. + * Returns the source code of this program. Note: sources are not cached, + * each call of this method calls into OpenCL. */ public String getSource() { return getProgramInfoString(CL.CL_PROGRAM_SOURCE); } + /** + * Returns the binaries for this program in a map containing the device as key + * and the byte array as value. + */ public Map<CLDevice, byte[]> getBinaries() { CLDevice[] devices = getCLDevices(); @@ -198,7 +250,7 @@ public class CLProgram { binarySize += (int)sizes.getLong(); ByteBuffer binaries = ByteBuffer.allocate(binarySize).order(ByteOrder.nativeOrder()); - ret = cl.clGetProgramInfo(ID, CL.CL_PROGRAM_BINARIES, binaries.capacity(), binaries, null, 0); // crash, driver bug? + ret = cl.clGetProgramInfo(ID, CL.CL_PROGRAM_BINARIES, binaries.capacity(), binaries, null, 0); // TODO crash, driver bug? checkForError(ret, "on clGetProgramInfo"); Map<CLDevice, byte[]> map = new HashMap<CLDevice, byte[]>(); @@ -212,59 +264,6 @@ public class CLProgram { return map; } - - // TODO serialization, program build options - - private final String getBuildInfoString(long device, int flag) { - - long[] longArray = new long[1]; - - int ret = cl.clGetProgramBuildInfo(ID, device, flag, 0, null, longArray, 0); - checkForError(ret, "on clGetProgramBuildInfo"); - - ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); - - ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); - checkForError(ret, "on clGetProgramBuildInfo"); - - return new String(bb.array(), 0, (int)longArray[0]); - } - - private final String getProgramInfoString(int flag) { - - long[] longArray = new long[1]; - - int ret = cl.clGetProgramInfo(ID, flag, 0, null, longArray, 0); - checkForError(ret, "on clGetProgramInfo"); - - ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); - - ret = cl.clGetProgramInfo(ID, flag, bb.capacity(), bb, null, 0); - checkForError(ret, "on clGetProgramInfo"); - - return new String(bb.array(), 0, (int)longArray[0]); - } - -// private int getProgramInfoInt(int flag) { -// -// ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); -// -// int ret = cl.clGetProgramInfo(programID, flag, bb.capacity(), bb, null, 0); -// checkForError(ret, ""); -// -// return bb.getInt(); -// } - - private int getBuildInfoInt(long device, int flag) { - - ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); - - int ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); - checkForError(ret, "error on clGetProgramBuildInfo"); - - return bb.getInt(); - } - @Override public boolean equals(Object obj) { if (obj == null) { @@ -290,5 +289,39 @@ public class CLProgram { hash = 37 * hash + (int) (this.ID ^ (this.ID >>> 32)); return hash; } + + public enum Status { + + BUILD_SUCCESS(CL.CL_BUILD_SUCCESS), + BUILD_NONE(CL.CL_BUILD_NONE), + BUILD_IN_PROGRESS(CL.CL_BUILD_IN_PROGRESS), + BUILD_ERROR(CL.CL_BUILD_ERROR); + + /** + * Value of wrapped OpenCL device type. + */ + public final int CL_BUILD_STATUS; + + private Status(int CL_BUILD_STATUS) { + this.CL_BUILD_STATUS = CL_BUILD_STATUS; + } + + public static Status valueOf(int clBuildStatus) { + switch(clBuildStatus) { + case(CL.CL_BUILD_SUCCESS): + return BUILD_SUCCESS; + case(CL.CL_BUILD_NONE): + return BUILD_NONE; + case(CL.CL_BUILD_IN_PROGRESS): + return BUILD_IN_PROGRESS; + case(CL.CL_BUILD_ERROR): + return BUILD_ERROR; +// is this a standard state? +// case (CL.CL_BUILD_PROGRAM_FAILURE): +// return BUILD_PROGRAM_FAILURE; + } + return null; + } + } } diff --git a/test/com/mbien/opencl/HighLevelBindingTest.java b/test/com/mbien/opencl/HighLevelBindingTest.java index 8ae61b2a..a0a2c13d 100644 --- a/test/com/mbien/opencl/HighLevelBindingTest.java +++ b/test/com/mbien/opencl/HighLevelBindingTest.java @@ -1,6 +1,6 @@ package com.mbien.opencl; -import com.mbien.opencl.CLBuffer.MEM; +import com.mbien.opencl.CLBuffer.Mem; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Map; @@ -35,6 +35,7 @@ public class HighLevelBindingTest { out.println("platform info:"); out.println(" name: "+platform.getName()); + out.println(" id: "+platform.ID); out.println(" profile: "+platform.getProfile()); out.println(" version: "+platform.getVersion()); out.println(" vendor: "+platform.getVendor()); @@ -62,7 +63,8 @@ public class HighLevelBindingTest { out.println(" - - - highLevelTest; global memory kernel - - - "); - CLContext context = CLContext.create(); +// CLPlatform[] clPlatforms = CLPlatform.listCLPlatforms(); + CLContext context = CLContext.create(/*clPlatforms[0]*/); CLDevice[] contextDevices = context.getCLDevices(); @@ -104,9 +106,9 @@ public class HighLevelBindingTest { fillBuffer(srcA, 23456); fillBuffer(srcB, 46987); - CLBuffer clBufferA = context.createBuffer(srcA, MEM.READ_ONLY); - CLBuffer clBufferB = context.createBuffer(srcB, MEM.READ_ONLY); - CLBuffer clBufferC = context.createBuffer(dest, MEM.WRITE_ONLY); + CLBuffer clBufferA = context.createBuffer(srcA, Mem.READ_ONLY); + CLBuffer clBufferB = context.createBuffer(srcB, Mem.READ_ONLY); + CLBuffer clBufferC = context.createBuffer(dest, Mem.WRITE_ONLY); Map<String, CLKernel> kernels = program.getCLKernels(); for (CLKernel kernel : kernels.values()) { @@ -169,8 +171,8 @@ public class HighLevelBindingTest { CLContext context = CLContext.create(); // the CL.MEM_* flag is probably completly irrelevant in our case since we do not use a kernel in this test - CLBuffer clBufferA = context.createBuffer(elements*SIZEOF_INT, MEM.READ_ONLY); - CLBuffer clBufferB = context.createBuffer(elements*SIZEOF_INT, MEM.READ_ONLY); + CLBuffer clBufferA = context.createBuffer(elements*SIZEOF_INT, Mem.READ_ONLY); + CLBuffer clBufferB = context.createBuffer(elements*SIZEOF_INT, Mem.READ_ONLY); // fill only first read buffer -> we will copy the payload to the second later. fillBuffer(clBufferA.buffer, 12345); diff --git a/test/com/mbien/opencl/LowLevelBindingTest.java b/test/com/mbien/opencl/LowLevelBindingTest.java index a746f977..3776a349 100644 --- a/test/com/mbien/opencl/LowLevelBindingTest.java +++ b/test/com/mbien/opencl/LowLevelBindingTest.java @@ -137,7 +137,7 @@ public class LowLevelBindingTest { int ret = CL.CL_SUCCESS; int[] intArray = new int[1]; - long context = cl.clCreateContextFromType(null, 0, CL.CL_DEVICE_TYPE_ALL, null, null, null, 0); + long context = cl.clCreateContextFromType(null, CL.CL_DEVICE_TYPE_ALL, null, null, null); out.println("context handle: "+context); ret = cl.clGetContextInfo(context, CL.CL_CONTEXT_DEVICES, 0, null, longArray, 0); |