diff options
Diffstat (limited to 'src/com/mbien/opencl/CLProgram.java')
-rw-r--r-- | src/com/mbien/opencl/CLProgram.java | 682 |
1 files changed, 0 insertions, 682 deletions
diff --git a/src/com/mbien/opencl/CLProgram.java b/src/com/mbien/opencl/CLProgram.java deleted file mode 100644 index db0b7304..00000000 --- a/src/com/mbien/opencl/CLProgram.java +++ /dev/null @@ -1,682 +0,0 @@ -package com.mbien.opencl; - -import com.mbien.opencl.util.CLProgramConfiguration; -import com.mbien.opencl.util.CLUtil; -import com.jogamp.common.nio.Int64Buffer; -import com.jogamp.common.os.Platform; -import com.jogamp.common.nio.PointerBuffer; -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Set; -import java.util.Map; - -import static com.mbien.opencl.CLException.*; -import static com.mbien.opencl.CL.*; -import static com.jogamp.common.nio.Buffers.*; - -/** - * Represents a OpenCL program executed on one or more {@link CLDevice}s. - * A CLProgram must be build using one of the build methods before creating {@link CLKernel}s. - * @see CLContext#createProgram(java.io.InputStream) - * @see CLContext#createProgram(java.lang.String) - * @see CLContext#createProgram(java.util.Map) - * @author Michael Bien - */ -public class CLProgram extends CLObject implements CLResource { - -// private final static Object buildLock = new Object(); - - private final Set<CLKernel> kernels; - private Map<CLDevice, Status> buildStatusMap; - - private boolean executable; - private boolean released; - - private CLProgram(CLContext context, long id) { - super(context, id); - this.kernels = new HashSet<CLKernel>(); - } - - static CLProgram create(CLContext context, String src) { - - IntBuffer status = newDirectByteBuffer(4).asIntBuffer(); - // Create the program - long id = context.cl.clCreateProgramWithSource(context.ID, 1, new String[] {src}, - (Int64Buffer)Int64Buffer.allocateDirect(1).put(src.length()), status); - - checkForError(status.get(), "can not create program with source"); - - return new CLProgram(context, id); - } - - static CLProgram create(CLContext context, Map<CLDevice, byte[]> binaries) { - - PointerBuffer devices = PointerBuffer.allocateDirect(binaries.size()); - PointerBuffer codeBuffers = PointerBuffer.allocateDirect(binaries.size()); - Int64Buffer lengths = Int64Buffer.allocateDirect(binaries.size()); - - int i = 0; - Set<CLDevice> keys = binaries.keySet(); - for (CLDevice device : keys) { - - byte[] bytes = binaries.get(device); - - devices.put(device.ID); - lengths.put(bytes.length); - - codeBuffers.referenceBuffer(i, newDirectByteBuffer(bytes)); - i++; - } - devices.rewind(); - lengths.rewind(); - - IntBuffer err = newDirectIntBuffer(1); -// IntBuffer status = newDirectByteBuffer(binaries.size()*4).asIntBuffer(); - long id = context.cl.clCreateProgramWithBinary(context.ID, devices.capacity(), devices, lengths, codeBuffers, /*status*/null, err); - -// while(status.remaining() != 0) { -// checkForError(status.get(), "unable to load binaries on all devices"); -// } - - checkForError(err.get(), "can not create program with binary"); - - return new CLProgram(context, id); - } - - private void initBuildStatus() { - - if(buildStatusMap == null) { -// synchronized(buildLock) { - Map<CLDevice, Status> map = new HashMap<CLDevice, Status>(); - CLDevice[] devices = getCLDevices(); - for (CLDevice device : devices) { - Status status = getBuildStatus(device); - if(status == Status.BUILD_SUCCESS) { - executable = true; - } - map.put(device, status); - } - this.buildStatusMap = Collections.unmodifiableMap(map); -// } - } - } - - private String getBuildInfoString(long device, int flag) { - - if(released) { - return ""; - } - - Int64Buffer size = Int64Buffer.allocateDirect(1); - - int ret = cl.clGetProgramBuildInfo(ID, device, flag, 0, null, size); - checkForError(ret, "on clGetProgramBuildInfo"); - - ByteBuffer buffer = newDirectByteBuffer((int)size.get(0)); - - ret = cl.clGetProgramBuildInfo(ID, device, flag, buffer.capacity(), buffer, null); - checkForError(ret, "on clGetProgramBuildInfo"); - - return CLUtil.clString2JavaString(buffer, (int)size.get(0)); - } - - private String getProgramInfoString(int flag) { - - if(released) { - return ""; - } - - Int64Buffer size = Int64Buffer.allocateDirect(1); - - int ret = cl.clGetProgramInfo(ID, flag, 0, null, size); - checkForError(ret, "on clGetProgramInfo"); - - ByteBuffer buffer = newDirectByteBuffer((int)size.get(0)); - - ret = cl.clGetProgramInfo(ID, flag, buffer.capacity(), buffer, null); - checkForError(ret, "on clGetProgramInfo"); - - return CLUtil.clString2JavaString(buffer, (int)size.get(0)); - } - -// private int getProgramInfoInt(int flag) { -// -// ByteBuffer bb = ByteBuffer.allocateDirect(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 buffer = newDirectByteBuffer(4); - - int ret = cl.clGetProgramBuildInfo(ID, device, flag, buffer.capacity(), buffer, null); - checkForError(ret, "error on clGetProgramBuildInfo"); - - return buffer.getInt(); - } - - - /** - * Builds this program for all devices associated with the context. - * @return this - */ - public CLProgram build() { - build(null, (CLDevice[])null); - return this; - } - - /** - * Builds this program for the given devices. - * @return this - * @param devices A list of devices this program should be build on or null for all devices of its context. - */ - public CLProgram build(CLDevice... devices) { - build(null, devices); - return this; - } - - /** - * Builds this program for all devices associated with the context using the specified build options. - * @see CompilerOptions - * @return this - */ - public CLProgram build(String options) { - build(options, (CLDevice[])null); - return this; - } - - /** - * Builds this program for all devices associated with the context using the specified build options. - * @see CompilerOptions - * @return this - */ - public CLProgram build(String... options) { - build(optionsOf(options), (CLDevice[])null); - return this; - } - - /** - * Builds this program for the given devices and with the specified build options. In case this program was - * already built and there are kernels associated with this program they will be released first before rebuild. - * @see CompilerOptions - * @return this - * @param devices A list of devices this program should be build on or null for all devices of its context. - */ - public CLProgram build(String options, CLDevice... devices) { - - if(released) { - throw new CLException("can not build a released program"); - } - - if(!kernels.isEmpty()) { - //No changes to the program executable are allowed while there are - //kernel objects associated with a program object. - releaseKernels(); - } - - PointerBuffer deviceIDs = null; - int count = 0; - if(devices != null && devices.length != 0) { - deviceIDs = PointerBuffer.allocateDirect(devices.length); - for (int i = 0; i < devices.length; i++) { - deviceIDs.put(i, devices[i].ID); - } - deviceIDs.rewind(); - count = devices.length; - } - - // nvidia driver doesn't like empty strings - if(options != null && options.trim().isEmpty()) { - options = null; - } - - // invalidate build status - buildStatusMap = null; - executable = false; - - // Build the program - int ret = 0; - // building programs is not threadsafe -// synchronized(buildLock) { - ret = cl.clBuildProgram(ID, count, deviceIDs, options, null, null); -// } - - if(ret != CL_SUCCESS) { - throw newException(ret, "\n"+getBuildLog()); - } - - return this; - } - - /** - * Prepares the build for this program by returning a new {@link CLProgramConfiguration}. - */ - public CLProgramConfiguration prepare() { - return CLProgramBuilder.createConfiguration(this); - } - - /** - * Creates a kernel with the specified kernel name. - */ - public CLKernel createCLKernel(String kernelName) { - - if(released) { - return null; - } - - int[] err = new int[1]; - long id = cl.clCreateKernel(ID, kernelName, err, 0); - checkForError(err[0], "unable to create Kernel with name: "+kernelName); - - CLKernel kernel = new CLKernel(this, id); - kernels.add(kernel); - return kernel; - } - - /** - * Creates all kernels of this program and stores them a Map with the kernel name as key. - */ - public Map<String, CLKernel> createCLKernels() { - - if(released) { - return Collections.emptyMap(); - } - - HashMap<String, CLKernel> newKernels = new HashMap<String, CLKernel>(); - - IntBuffer numKernels = newDirectByteBuffer(4).asIntBuffer(); - int ret = cl.clCreateKernelsInProgram(ID, 0, null, numKernels); - checkForError(ret, "can not create kernels for program"); - - if(numKernels.get(0) > 0) { - - PointerBuffer kernelIDs = PointerBuffer.allocateDirect(numKernels.get(0)); - ret = cl.clCreateKernelsInProgram(ID, kernelIDs.capacity(), kernelIDs, null); - checkForError(ret, "can not create kernels for program"); - - for (int i = 0; i < kernelIDs.capacity(); i++) { - CLKernel kernel = new CLKernel(this, kernelIDs.get(i)); - kernels.add(kernel); - newKernels.put(kernel.name, kernel); - } - }else{ - initBuildStatus(); - if(!isExecutable()) { - // It is illegal to create kernels from a not executable program. - // For consistency between AMD and NVIDIA drivers throw an exception at this point. - throw newException(CL_INVALID_PROGRAM_EXECUTABLE, - "can not initialize kernels, program is not executable. status: "+buildStatusMap); - } - } - - return newKernels; - } - - void onKernelReleased(CLKernel kernel) { - this.kernels.remove(kernel); - } - - /** - * Releases this program with its kernels. - */ - public void release() { - - releaseKernels(); - - executable = false; - released = true; - buildStatusMap = null; - - int ret = cl.clReleaseProgram(ID); - context.onProgramReleased(this); - checkForError(ret, "can not release program"); - } - - public void close() { - release(); - } - - private void releaseKernels() { - if(!kernels.isEmpty()) { - // copy to array to prevent concurrent modification exception - CLKernel[] array = kernels.toArray(new CLKernel[kernels.size()]); - for (CLKernel kernel : array) { - kernel.release(); - } - } - } - - /** - * Returns all devices associated with this program. - */ - public CLDevice[] getCLDevices() { - if(released) { - return new CLDevice[0]; - } - Int64Buffer size = Int64Buffer.allocateDirect(1); - int ret = cl.clGetProgramInfo(ID, CL_PROGRAM_DEVICES, 0, null, size); - checkForError(ret, "on clGetProgramInfo"); - - ByteBuffer bb = newDirectByteBuffer((int) size.get(0)); - ret = cl.clGetProgramInfo(ID, CL_PROGRAM_DEVICES, bb.capacity(), bb, null); - checkForError(ret, "on clGetProgramInfo"); - - int count = bb.capacity() / (Platform.is32Bit()?4:8); - CLDevice[] devices = new CLDevice[count]; - for (int i = 0; i < count; i++) { - devices[i] = context.getDevice(Platform.is32Bit()?bb.getInt():bb.getLong()); - } - - return devices; - - } - - /** - * Returns the build log of this program on all devices. The contents of the log are - * implementation dependent. - */ - public String getBuildLog() { - if(released) { - return ""; - } - StringBuilder sb = new StringBuilder(); - CLDevice[] devices = getCLDevices(); - for (int i = 0; i < devices.length; i++) { - CLDevice device = devices[i]; - sb.append(device).append(" build log:\n"); - String log = getBuildLog(device).trim(); - sb.append(log.isEmpty()?" <empty>":log); - if(i != devices.length-1) - sb.append("\n"); - } - return sb.toString(); - } - - /** - * Returns the build status enum of this program for each device as Map. - */ - public Map<CLDevice,Status> getBuildStatus() { - if(released) { - return Collections.emptyMap(); - } - initBuildStatus(); - return buildStatusMap; - } - - /** - * Returns true if the build status 'BUILD_SUCCESS' for at least one device - * of this program exists. - */ - public boolean isExecutable() { - if(released) { - return false; - } - initBuildStatus(); - return executable; - } - - /** - * Returns the build log for this program on the specified device. The contents - * of the log are implementation dependent log can be an empty String. - */ - public String getBuildLog(CLDevice device) { - return getBuildInfoString(device.ID, CL_PROGRAM_BUILD_LOG); - } - - /** - * Returns the build status enum for this program on the specified device. - */ - public Status getBuildStatus(CLDevice device) { - if(released) { - return Status.BUILD_NONE; - } - int clStatus = getBuildInfoInt(device.ID, 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 Open - */ - public String getSource() { - return getProgramInfoString(CL_PROGRAM_SOURCE); - } - - /** - * Returns the binaries for this program in an ordered Map containing the device as key - * and the program binaries as value. - */ - public Map<CLDevice, byte[]> getBinaries() { - - if(!isExecutable()) { - return Collections.emptyMap(); - } - - CLDevice[] devices = getCLDevices(); - - ByteBuffer sizes = newDirectByteBuffer(8*devices.length); - int ret = cl.clGetProgramInfo(ID, CL_PROGRAM_BINARY_SIZES, sizes.capacity(), sizes, null); - checkForError(ret, "on clGetProgramInfo"); - - int binariesSize = 0; - while(sizes.remaining() != 0) { - int size = (int) sizes.getLong(); - binariesSize += size; - } - ByteBuffer binaries = newDirectByteBuffer(binariesSize); - - - long address = InternalBufferUtil.getDirectBufferAddress(binaries); - PointerBuffer addresses = PointerBuffer.allocateDirect(sizes.capacity()); - sizes.rewind(); - while(sizes.remaining() != 0) { - addresses.put(address); - address += sizes.getLong(); - } - - ret = cl.clGetProgramInfo(ID, CL_PROGRAM_BINARIES, addresses.capacity(), addresses.getBuffer(), null); - checkForError(ret, "on clGetProgramInfo"); - - Map<CLDevice, byte[]> map = new LinkedHashMap<CLDevice, byte[]>(); - sizes.rewind(); - for (int i = 0; i < devices.length; i++) { - byte[] bytes = new byte[(int)sizes.getLong()]; - binaries.get(bytes); - map.put(devices[i], bytes); - } - - return map; - } - - /** - * Utility method which builds a properly seperated option string. - */ - public static String optionsOf(String... options) { - StringBuilder sb = new StringBuilder(options.length * 24); - for (int i = 0; i < options.length; i++) { - sb.append(options[i]); - if(i!= options.length-1) - sb.append(" "); - } - return sb.toString(); - } - - /** - * Utility method for defining macros as build options (Returns "-D name"). - */ - public static String define(String name) { - return "-D "+name; - } - - /** - * Utility method for defining macros as build options (Returns "-D name=value"). - */ - public static String define(String name, Object value) { - return "-D "+name+"="+value; - } - - @Override - public String toString() { - return "CLProgram [id: " + ID - + " status: "+getBuildStatus()+"]"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final CLProgram other = (CLProgram) obj; - if (this.ID != other.ID) { - return false; - } - if (!this.context.equals(other.context)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 37 * hash + (this.context != null ? this.context.hashCode() : 0); - hash = 37 * hash + (int) (this.ID ^ (this.ID >>> 32)); - return hash; - } - - public enum Status { - - BUILD_SUCCESS(CL_BUILD_SUCCESS), - BUILD_NONE(CL_BUILD_NONE), - BUILD_IN_PROGRESS(CL_BUILD_IN_PROGRESS), - BUILD_ERROR(CL_BUILD_ERROR); - - /** - * Value of wrapped OpenCL device type. - */ - public final int STATUS; - - private Status(int status) { - this.STATUS = status; - } - - public static Status valueOf(int clBuildStatus) { - switch(clBuildStatus) { - case(CL_BUILD_SUCCESS): - return BUILD_SUCCESS; - case(CL_BUILD_NONE): - return BUILD_NONE; - case(CL_BUILD_IN_PROGRESS): - return BUILD_IN_PROGRESS; - case(CL_BUILD_ERROR): - return BUILD_ERROR; -// is this a standard state? -// case (CL_BUILD_PROGRAM_FAILURE): -// return BUILD_PROGRAM_FAILURE; - } - return null; - } - } - - /** - * Common compiler options for the OpenCL compiler. - */ - public interface CompilerOptions { - - /** - * Treat double precision floating-point constant as single precision constant. - */ - public final static String SINGLE_PRECISION_CONSTANTS = "-cl-single-precision-constant"; - - /** - * This option controls how single precision and double precision denormalized numbers are handled. - * If specified as a build option, the single precision denormalized numbers may be flushed to zero - * and if the optional extension for double precision is supported, double precision denormalized numbers - * may also be flushed to zero. This is intended to be a performance hint and the OpenCL compiler can choose - * not to flush denorms to zero if the device supports single precision (or double precision) denormalized numbers.<br> - * This option is ignored for single precision numbers if the device does not support single precision denormalized - * numbers i.e. {@link CLDevice.FPConfig#DENORM} is not present in the set returned by {@link CLDevice#getSingleFPConfig()}<br> - * This option is ignored for double precision numbers if the device does not support double precision or if it does support - * double precision but {@link CLDevice.FPConfig#DENORM} is not present in the set returned by {@link CLDevice#getDoubleFPConfig()}.<br> - * This flag only applies for scalar and vector single precision floating-point variables and computations on - * these floating-point variables inside a program. It does not apply to reading from or writing to image objects. - */ - public final static String DENORMS_ARE_ZERO = "-cl-denorms-are-zero"; - - /** - * This option disables all optimizations. The default is optimizations are enabled. - */ - public final static String DISABLE_OPT = "-cl-opt-disable"; - - /** - * This option allows the compiler to assume the strictest aliasing rules. - */ - public final static String STRICT_ALIASING = "-cl-strict-aliasing"; - - /** - * Allow a * b + c to be replaced by a mad. The mad computes a * b + c with reduced accuracy. - * For example, some OpenCL devices implement mad as truncate the result of a * b before adding it to c. - */ - public final static String ENABLE_MAD = "-cl-mad-enable"; - - /** - * Allow optimizations for floating-point arithmetic that ignore the signedness of zero. - * IEEE 754 arithmetic specifies the behavior of distinct +0.0 and -0.0 values, which then prohibits - * simplification of expressions such as x+0.0 or 0.0*x (even with -cl-finite-math-only ({@link #FINITE_MATH_ONLY})). - * This option implies that the sign of a zero result isn't significant. - */ - public final static String NO_SIGNED_ZEROS = "-cl-no-signed-zeros"; - - /** - * Allow optimizations for floating-point arithmetic that<br> - * (a) assume that arguments and results are valid,<br> - * (b) may violate IEEE 754 standard and<br> - * (c) may violate the OpenCL numerical compliance requirements as defined in section - * 7.4 for single-precision floating-point, section 9.3.9 for double-precision floating-point, - * and edge case behavior in section 7.5. - * This option includes the -cl-no-signed-zeros ({@link #NO_SIGNED_ZEROS}) - * and -cl-mad-enable ({@link #ENABLE_MAD}) options. - */ - public final static String UNSAFE_MATH = "-cl-unsafe-math-optimizations"; - - /** - * Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or ±∞. - * This option may violate the OpenCL numerical compliance requirements defined in in section 7.4 for - * single-precision floating-point, section 9.3.9 for double-precision floating-point, and edge case behavior in section 7.5. - */ - public final static String FINITE_MATH_ONLY = "-cl-finite-math-only"; - - /** - * Sets the optimization options -cl-finite-math-only ({@link #FINITE_MATH_ONLY}) and -cl-unsafe-math-optimizations ({@link #UNSAFE_MATH}). - * This allows optimizations for floating-point arithmetic that may violate the IEEE 754 - * standard and the OpenCL numerical compliance requirements defined in the specification - * in section 7.4 for single-precision floating-point, section 9.3.9 for double-precision - * floating-point, and edge case behavior in section 7.5. This option causes the preprocessor - * macro __FAST_RELAXED_MATH__ to be defined in the OpenCL program. - */ - public final static String FAST_RELAXED_MATH = "-cl-fast-relaxed-math"; - - /** - * Inhibit all warning messages. - */ - public final static String DISABLE_WARNINGS = "-w"; - - /** - * Make all warnings into errors. - */ - public final static String WARNINGS_ARE_ERRORS = "-Werror"; - - } - -} |