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 }