View Javadoc
1   package net.bmahe.genetics4j.gpu.opencl;
2   
3   import java.util.Arrays;
4   import java.util.List;
5   import java.util.Objects;
6   
7   import org.apache.commons.lang3.Validate;
8   import org.jocl.CL;
9   import org.jocl.Pointer;
10  import org.jocl.cl_platform_id;
11  
12  /**
13   * Utility class providing convenient methods for OpenCL platform discovery and information queries.
14   * 
15   * <p>PlatformUtils encapsulates the low-level OpenCL API calls required for platform enumeration and property
16   * retrieval, providing a higher-level interface for GPU-accelerated evolutionary algorithm implementations. This class
17   * handles the OpenCL buffer management and type conversions necessary for interacting with the native OpenCL runtime.
18   * 
19   * <p>Key functionality includes:
20   * <ul>
21   * <li><strong>Platform enumeration</strong>: Discover available OpenCL platforms in the system</li>
22   * <li><strong>Property queries</strong>: Retrieve platform characteristics and capabilities</li>
23   * <li><strong>Device counting</strong>: Count available devices on each platform</li>
24   * <li><strong>Buffer management</strong>: Handle memory allocation for OpenCL information queries</li>
25   * </ul>
26   * 
27   * <p>Common usage patterns:
28   * 
29   * <pre>{@code
30   * // Enumerate platforms in the system
31   * int platformCount = PlatformUtils.numPlatforms();
32   * List<cl_platform_id> platformIds = PlatformUtils.platformIds(platformCount);
33   * 
34   * // Query platform properties
35   * for (cl_platform_id platformId : platformIds) {
36   * 	String platformName = PlatformUtils.getStringParameter(platformId, CL.CL_PLATFORM_NAME);
37   * 	String vendor = PlatformUtils.getStringParameter(platformId, CL.CL_PLATFORM_VENDOR);
38   * 	String version = PlatformUtils.getStringParameter(platformId, CL.CL_PLATFORM_VERSION);
39   * 
40   * 	// Count devices on this platform
41   * 	int deviceCount = PlatformUtils.numDevices(platformId);
42   * 	int gpuCount = PlatformUtils.numDevices(platformId, CL.CL_DEVICE_TYPE_GPU);
43   * }
44   * }</pre>
45   * 
46   * <p>Platform discovery workflow:
47   * <ol>
48   * <li><strong>System enumeration</strong>: Query the number of available platforms</li>
49   * <li><strong>Platform retrieval</strong>: Get platform identifiers for all available platforms</li>
50   * <li><strong>Property queries</strong>: Retrieve platform characteristics for filtering</li>
51   * <li><strong>Device counting</strong>: Determine available devices for each platform</li>
52   * </ol>
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   * <li><strong>Empty platform handling</strong>: Gracefully handles systems with no OpenCL platforms</li>
60   * </ul>
61   * 
62   * @see Platform
63   * @see PlatformReader
64   * @see net.bmahe.genetics4j.gpu.opencl.model.PlatformProfile
65   */
66  public class PlatformUtils {
67  
68  	private PlatformUtils() {
69  
70  	}
71  
72  	/**
73  	 * Returns the number of OpenCL platforms available in the system.
74  	 * 
75  	 * @return the number of available OpenCL platforms
76  	 */
77  	public static int numPlatforms() {
78  		final int[] numPlatforms = new int[1];
79  		CL.clGetPlatformIDs(0, null, numPlatforms);
80  
81  		return numPlatforms[0];
82  	}
83  
84  	/**
85  	 * Returns a list of OpenCL platform identifiers for all available platforms.
86  	 * 
87  	 * @param numPlatforms the number of platforms to retrieve
88  	 * @return list of OpenCL platform identifiers, or empty list if numPlatforms is 0
89  	 * @throws IllegalArgumentException if numPlatforms is negative
90  	 */
91  	public static List<cl_platform_id> platformIds(final int numPlatforms) {
92  		Validate.isTrue(numPlatforms >= 0);
93  
94  		if (numPlatforms == 0) {
95  			return List.of();
96  		}
97  
98  		final cl_platform_id[] platformIds = new cl_platform_id[numPlatforms];
99  		CL.clGetPlatformIDs(platformIds.length, platformIds, null);
100 
101 		return Arrays.asList(platformIds);
102 	}
103 
104 	/**
105 	 * Queries and returns a string property of the specified OpenCL platform.
106 	 * 
107 	 * <p>This method handles the OpenCL API calls and buffer management required to retrieve string properties from
108 	 * platforms, such as platform name, vendor, or version information.
109 	 * 
110 	 * @param platformId   the OpenCL platform to query
111 	 * @param platformName the OpenCL parameter constant (e.g., CL_PLATFORM_NAME, CL_PLATFORM_VENDOR)
112 	 * @return the string value of the requested platform property
113 	 * @throws IllegalArgumentException if platformId is null
114 	 */
115 	public static String getStringParameter(final cl_platform_id platformId, final int platformName) {
116 		Objects.requireNonNull(platformId);
117 
118 		final long[] parameterSize = new long[1];
119 		CL.clGetPlatformInfo(platformId, platformName, 0, null, parameterSize);
120 
121 		final byte[] buffer = new byte[(int) parameterSize[0]];
122 		CL.clGetPlatformInfo(platformId, platformName, buffer.length, Pointer.to(buffer), null);
123 
124 		return new String(buffer, 0, buffer.length - 1);
125 	}
126 
127 	/**
128 	 * Returns the number of OpenCL devices of the specified type available on the platform.
129 	 * 
130 	 * @param platformId the OpenCL platform to query
131 	 * @param deviceType the type of devices to count (e.g., CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_ALL)
132 	 * @return the number of available devices of the specified type
133 	 * @throws IllegalArgumentException if platformId is null
134 	 */
135 	public static int numDevices(final cl_platform_id platformId, final long deviceType) {
136 		Objects.requireNonNull(platformId);
137 
138 		int[] numDevices = new int[1];
139 		CL.clGetDeviceIDs(platformId, deviceType, 0, null, numDevices);
140 
141 		return numDevices[0];
142 	}
143 
144 	/**
145 	 * Returns the total number of OpenCL devices available on the platform.
146 	 * 
147 	 * <p>This is equivalent to calling {@link #numDevices(cl_platform_id, long)} with {@code CL_DEVICE_TYPE_ALL} as the
148 	 * device type.
149 	 * 
150 	 * @param platformId the OpenCL platform to query
151 	 * @return the total number of available devices on the platform
152 	 * @throws IllegalArgumentException if platformId is null
153 	 */
154 	public static int numDevices(final cl_platform_id platformId) {
155 		Objects.requireNonNull(platformId);
156 
157 		return numDevices(platformId, CL.CL_DEVICE_TYPE_ALL);
158 	}
159 }