1 package net.bmahe.genetics4j.gpu.opencl; 2 3 import java.util.Arrays; 4 import java.util.List; 5 6 import org.apache.commons.lang3.Validate; 7 import org.jocl.CL; 8 import org.jocl.Pointer; 9 import org.jocl.Sizeof; 10 import org.jocl.cl_device_id; 11 import org.jocl.cl_platform_id; 12 13 /** 14 * Utility class providing convenient methods for OpenCL device discovery and information queries. 15 * 16 * <p>DeviceUtils encapsulates the low-level OpenCL API calls required for device enumeration and 17 * property retrieval, providing a higher-level interface for GPU-accelerated evolutionary algorithm 18 * implementations. This class handles the OpenCL buffer management and type conversions necessary 19 * for interacting with the native OpenCL runtime. 20 * 21 * <p>Key functionality includes: 22 * <ul> 23 * <li><strong>Device enumeration</strong>: Discover available devices on OpenCL platforms</li> 24 * <li><strong>Property queries</strong>: Retrieve device characteristics and capabilities</li> 25 * <li><strong>Type conversions</strong>: Convert between OpenCL native types and Java types</li> 26 * <li><strong>Buffer management</strong>: Handle memory allocation for OpenCL information queries</li> 27 * </ul> 28 * 29 * <p>Common usage patterns: 30 * <pre>{@code 31 * // Enumerate devices on a platform 32 * int deviceCount = DeviceUtils.numDevices(platformId); 33 * List<cl_device_id> deviceIds = DeviceUtils.getDeviceIds(platformId, deviceCount); 34 * 35 * // Query device properties 36 * String deviceName = DeviceUtils.getDeviceInfoString(deviceId, CL.CL_DEVICE_NAME); 37 * int computeUnits = DeviceUtils.getDeviceInfoInt(deviceId, CL.CL_DEVICE_MAX_COMPUTE_UNITS); 38 * long maxWorkGroupSize = DeviceUtils.getDeviceInfoLong(deviceId, CL.CL_DEVICE_MAX_WORK_GROUP_SIZE); 39 * 40 * // Query array properties 41 * int maxDimensions = DeviceUtils.getDeviceInfoInt(deviceId, CL.CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS); 42 * long[] maxWorkItemSizes = DeviceUtils.getDeviceInfoLongArray(deviceId, 43 * CL.CL_DEVICE_MAX_WORK_ITEM_SIZES, maxDimensions); 44 * }</pre> 45 * 46 * <p>Device type filtering: 47 * <ul> 48 * <li><strong>CL_DEVICE_TYPE_ALL</strong>: All available devices</li> 49 * <li><strong>CL_DEVICE_TYPE_GPU</strong>: GPU devices only</li> 50 * <li><strong>CL_DEVICE_TYPE_CPU</strong>: CPU devices only</li> 51 * <li><strong>CL_DEVICE_TYPE_ACCELERATOR</strong>: Accelerator devices only</li> 52 * </ul> 53 * 54 * <p>Error handling: 55 * <ul> 56 * <li><strong>Parameter validation</strong>: Validates all input parameters</li> 57 * <li><strong>OpenCL error propagation</strong>: OpenCL errors are propagated as runtime exceptions</li> 58 * <li><strong>Memory management</strong>: Automatically handles buffer allocation and cleanup</li> 59 * </ul> 60 * 61 * @see Device 62 * @see DeviceReader 63 * @see net.bmahe.genetics4j.gpu.opencl.model.DeviceType 64 */ 65 public class DeviceUtils { 66 67 private DeviceUtils() { 68 69 } 70 71 /** 72 * Returns the number of OpenCL devices of the specified type available on the platform. 73 * 74 * @param platformId the OpenCL platform to query 75 * @param deviceType the type of devices to count (e.g., CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_ALL) 76 * @return the number of available devices of the specified type 77 * @throws IllegalArgumentException if platformId is null 78 */ 79 public static int numDevices(final cl_platform_id platformId, final long deviceType) { 80 Validate.notNull(platformId); 81 82 final int numDevices[] = new int[1]; 83 CL.clGetDeviceIDs(platformId, deviceType, 0, null, numDevices); 84 85 return numDevices[0]; 86 } 87 88 /** 89 * Returns the total number of OpenCL devices available on the platform. 90 * 91 * <p>This is equivalent to calling {@link #numDevices(cl_platform_id, long)} with 92 * {@code CL_DEVICE_TYPE_ALL} as the device type. 93 * 94 * @param platformId the OpenCL platform to query 95 * @return the total number of available devices on the platform 96 * @throws IllegalArgumentException if platformId is null 97 */ 98 public static int numDevices(final cl_platform_id platformId) { 99 return numDevices(platformId, CL.CL_DEVICE_TYPE_ALL); 100 } 101 102 /** 103 * Returns a list of OpenCL device identifiers of the specified type from the platform. 104 * 105 * @param platformId the OpenCL platform to query 106 * @param numDevices the number of devices to retrieve 107 * @param deviceType the type of devices to retrieve (e.g., CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_ALL) 108 * @return list of OpenCL device identifiers 109 * @throws IllegalArgumentException if platformId is null or numDevices is not positive 110 */ 111 public static List<cl_device_id> getDeviceIds(final cl_platform_id platformId, final int numDevices, 112 final long deviceType) { 113 Validate.notNull(platformId); 114 Validate.isTrue(numDevices > 0); 115 116 cl_device_id deviceIds[] = new cl_device_id[numDevices]; 117 CL.clGetDeviceIDs(platformId, deviceType, numDevices, deviceIds, null); 118 119 return Arrays.asList(deviceIds); 120 } 121 122 /** 123 * Returns a list of all OpenCL device identifiers from the platform. 124 * 125 * <p>This is equivalent to calling {@link #getDeviceIds(cl_platform_id, int, long)} with 126 * {@code CL_DEVICE_TYPE_ALL} as the device type. 127 * 128 * @param platformId the OpenCL platform to query 129 * @param numDevices the number of devices to retrieve 130 * @return list of all OpenCL device identifiers 131 * @throws IllegalArgumentException if platformId is null or numDevices is not positive 132 */ 133 public static List<cl_device_id> getDeviceIds(final cl_platform_id platformId, final int numDevices) { 134 return getDeviceIds(platformId, numDevices, CL.CL_DEVICE_TYPE_ALL); 135 } 136 137 /** 138 * Queries and returns a string property of the specified OpenCL device. 139 * 140 * <p>This method handles the OpenCL API calls and buffer management required to retrieve 141 * string properties from devices, such as device name, vendor, or version information. 142 * 143 * @param deviceId the OpenCL device to query 144 * @param parameter the OpenCL parameter constant (e.g., CL_DEVICE_NAME, CL_DEVICE_VENDOR) 145 * @return the string value of the requested device property 146 * @throws IllegalArgumentException if deviceId is null 147 */ 148 public static String getDeviceInfoString(final cl_device_id deviceId, final int parameter) { 149 Validate.notNull(deviceId); 150 151 final long[] size = new long[1]; 152 CL.clGetDeviceInfo(deviceId, parameter, 0, null, size); 153 154 final byte[] buffer = new byte[(int) size[0]]; 155 CL.clGetDeviceInfo(deviceId, parameter, buffer.length, Pointer.to(buffer), null); 156 157 return new String(buffer, 0, buffer.length - 1); 158 } 159 160 /** 161 * Queries and returns a long array property of the specified OpenCL device. 162 * 163 * <p>This method is useful for retrieving array properties such as maximum work-item sizes 164 * per dimension, which require multiple values to fully describe the device capability. 165 * 166 * @param deviceId the OpenCL device to query 167 * @param parameter the OpenCL parameter constant (e.g., CL_DEVICE_MAX_WORK_ITEM_SIZES) 168 * @param size the number of long values to retrieve 169 * @return array of long values for the requested device property 170 * @throws IllegalArgumentException if deviceId is null or size is not positive 171 */ 172 public static long[] getDeviceInfoLongArray(final cl_device_id deviceId, final int parameter, final int size) { 173 Validate.notNull(deviceId); 174 Validate.isTrue(size > 0); 175 176 final long[] values = new long[size]; 177 CL.clGetDeviceInfo(deviceId, parameter, Sizeof.cl_long * size, Pointer.to(values), null); 178 179 return values; 180 } 181 182 /** 183 * Queries and returns a single long property of the specified OpenCL device. 184 * 185 * <p>This method is useful for retrieving single long value properties such as maximum 186 * work group size, global memory size, or local memory size. 187 * 188 * @param deviceId the OpenCL device to query 189 * @param parameter the OpenCL parameter constant (e.g., CL_DEVICE_MAX_WORK_GROUP_SIZE) 190 * @return the long value of the requested device property 191 * @throws IllegalArgumentException if deviceId is null 192 */ 193 public static long getDeviceInfoLong(final cl_device_id deviceId, final int parameter) { 194 Validate.notNull(deviceId); 195 196 final long[] values = getDeviceInfoLongArray(deviceId, parameter, 1); 197 198 return values[0]; 199 } 200 201 /** 202 * Queries and returns a single integer property of the specified OpenCL device. 203 * 204 * <p>This method is useful for retrieving integer properties such as maximum compute units, 205 * maximum clock frequency, or maximum work-item dimensions. 206 * 207 * @param deviceId the OpenCL device to query 208 * @param parameter the OpenCL parameter constant (e.g., CL_DEVICE_MAX_COMPUTE_UNITS) 209 * @return the integer value of the requested device property 210 * @throws IllegalArgumentException if deviceId is null 211 */ 212 public static int getDeviceInfoInt(final cl_device_id deviceId, final int parameter) { 213 Validate.notNull(deviceId); 214 215 final int[] values = new int[1]; 216 CL.clGetDeviceInfo(deviceId, parameter, Sizeof.cl_int, Pointer.to(values), null); 217 218 return values[0]; 219 } 220 }