1 package net.bmahe.genetics4j.gpu.spec;
2
3 import java.util.List;
4 import java.util.Objects;
5 import java.util.Optional;
6 import java.util.Set;
7
8 import org.apache.commons.lang3.Validate;
9 import org.immutables.value.Value;
10
11 /**
12 * Specification for OpenCL programs containing kernel source code, build options, and compilation settings.
13 *
14 * <p>Program represents a complete OpenCL program specification that includes kernel source code (either as direct
15 * content or resource references), kernel definitions, and compilation options. This specification is used by the GPU
16 * EA system to compile and execute OpenCL kernels for fitness evaluation on GPU devices.
17 *
18 * <p>A program can contain:
19 * <ul>
20 * <li><strong>Source content</strong>: Direct OpenCL C code as strings</li>
21 * <li><strong>Resource references</strong>: Paths to OpenCL source files in the classpath</li>
22 * <li><strong>Kernel definitions</strong>: Names of kernels to be compiled and made available</li>
23 * <li><strong>Build options</strong>: Compiler flags and preprocessor definitions</li>
24 * </ul>
25 *
26 * <p>Program compilation workflow:
27 * <ol>
28 * <li><strong>Source loading</strong>: Load content from strings and resource files</li>
29 * <li><strong>Source concatenation</strong>: Combine all sources into a single compilation unit</li>
30 * <li><strong>Compilation</strong>: Compile with specified build options for target devices</li>
31 * <li><strong>Kernel extraction</strong>: Create kernel objects for specified kernel names</li>
32 * <li><strong>Validation</strong>: Verify all kernels were successfully created</li>
33 * </ol>
34 *
35 * <p>Common usage patterns:
36 *
37 * <pre>{@code
38 * // Simple single-kernel program from resource
39 * Program basicProgram = Program.ofResource("/kernels/fitness.cl", "evaluate_fitness");
40 *
41 * // Program with build options for optimization
42 * Program optimizedProgram = Program
43 * .ofResource("/kernels/optimization.cl", "fitness_kernel", "-O3 -DPOPULATION_SIZE=1000 -DUSE_FAST_MATH");
44 *
45 * // Complex program with multiple sources and kernels
46 * Program complexProgram = Program.builder()
47 * .addContent("#define PROBLEM_SIZE 256") // Direct content
48 * .addResources("/kernels/common.cl") // Common utilities
49 * .addResources("/kernels/fitness.cl") // Main fitness logic
50 * .addKernelNames("fitness_eval") // Primary kernel
51 * .addKernelNames("data_preparation") // Helper kernel
52 * .buildOptions("-cl-fast-relaxed-math -DLOCAL_SIZE=64")
53 * .build();
54 * }</pre>
55 *
56 * <p>Build options support:
57 * <ul>
58 * <li><strong>Optimization flags</strong>: -O0, -O1, -O2, -O3 for performance tuning</li>
59 * <li><strong>Math optimizations</strong>: -cl-fast-relaxed-math for numerical performance</li>
60 * <li><strong>Preprocessor definitions</strong>: -DMACRO=value for compile-time configuration</li>
61 * <li><strong>Warning control</strong>: -w to disable warnings, -Werror to treat warnings as errors</li>
62 * <li><strong>Standards compliance</strong>: -cl-std=CL1.2 for specific OpenCL version targeting</li>
63 * </ul>
64 *
65 * <p>Resource loading considerations:
66 * <ul>
67 * <li><strong>Classpath resolution</strong>: Resources loaded relative to classpath</li>
68 * <li><strong>Encoding</strong>: Source files assumed to be UTF-8 encoded</li>
69 * <li><strong>Include simulation</strong>: Manual concatenation instead of OpenCL #include</li>
70 * <li><strong>Error handling</strong>: Resource loading failures result in compilation errors</li>
71 * </ul>
72 *
73 * <p>Validation and constraints:
74 * <ul>
75 * <li><strong>Kernel names required</strong>: At least one kernel name must be specified</li>
76 * <li><strong>Source availability</strong>: Either content or resources must provide source code</li>
77 * <li><strong>Name uniqueness</strong>: Kernel names must be unique within the program</li>
78 * <li><strong>Compilation validity</strong>: Source code must compile successfully for target devices</li>
79 * </ul>
80 *
81 * @see net.bmahe.genetics4j.gpu.GPUFitnessEvaluator
82 * @see net.bmahe.genetics4j.gpu.spec.GPUEAConfiguration
83 * @see net.bmahe.genetics4j.gpu.opencl.OpenCLExecutionContext
84 */
85 @Value.Immutable
86 public abstract class Program {
87
88 /**
89 * Returns the direct OpenCL source code content as strings.
90 *
91 * <p>Content represents OpenCL C source code provided directly as strings rather than loaded from resources.
92 * Multiple content strings are concatenated during compilation to form a single compilation unit.
93 *
94 * @return list of OpenCL source code strings
95 */
96 @Value.Parameter
97 public abstract List<String> content();
98
99 /**
100 * Returns the classpath resource paths containing OpenCL source code.
101 *
102 * <p>Resources are loaded from the classpath at compilation time and concatenated with any direct content to form
103 * the complete program source. Resource paths should be relative to the classpath root.
104 *
105 * @return set of classpath resource paths for OpenCL source files
106 */
107 @Value.Parameter
108 public abstract Set<String> resources();
109
110 /**
111 * Returns the names of kernels to be extracted from the compiled program.
112 *
113 * <p>Kernel names specify which functions in the OpenCL source should be made available as executable kernels. These
114 * names must correspond to functions declared with the {@code __kernel} qualifier in the source code.
115 *
116 * @return set of kernel function names to extract after compilation
117 */
118 @Value.Parameter
119 public abstract Set<String> kernelNames();
120
121 /**
122 * Returns the OpenCL compiler build options for program compilation.
123 *
124 * <p>Build options are passed to the OpenCL compiler to control optimization, define preprocessor macros, and
125 * configure compilation behavior. Common options include optimization levels, math optimizations, and macro
126 * definitions.
127 *
128 * @return optional build options string for OpenCL compilation
129 */
130 public abstract Optional<String> buildOptions();
131
132 @Value.Check
133 protected void check() {
134 Objects.requireNonNull(kernelNames());
135 Validate.isTrue(kernelNames().isEmpty() == false, "At least one kernel name must be specified");
136 }
137
138 /**
139 * Creates a program from direct OpenCL source content with a single kernel.
140 *
141 * <p>This factory method creates a simple program specification with source code provided directly as a string and a
142 * single kernel to be extracted.
143 *
144 * @param content the OpenCL source code as a string
145 * @param kernelName the name of the kernel function to extract
146 * @return a new program specification with the given content and kernel
147 * @throws IllegalArgumentException if content or kernelName is null or blank
148 */
149 public static Program ofContent(final String content, final String kernelName) {
150 Validate.notBlank(content);
151 Validate.notBlank(kernelName);
152
153 return ImmutableProgram.builder().addContent(content).addKernelNames(kernelName).build();
154 }
155
156 /**
157 * Creates a program from a classpath resource with a single kernel.
158 *
159 * <p>This factory method creates a program specification that loads OpenCL source code from a classpath resource and
160 * extracts a single named kernel.
161 *
162 * @param resource the classpath path to the OpenCL source file
163 * @param kernelName the name of the kernel function to extract
164 * @return a new program specification with the given resource and kernel
165 * @throws IllegalArgumentException if resource or kernelName is null or blank
166 */
167 public static Program ofResource(final String resource, final String kernelName) {
168 Validate.notBlank(resource);
169 Validate.notBlank(kernelName);
170
171 return ImmutableProgram.builder().addResources(resource).addKernelNames(kernelName).build();
172 }
173
174 /**
175 * Creates a program from a classpath resource with a single kernel and build options.
176 *
177 * <p>This factory method creates a program specification that loads OpenCL source code from a classpath resource,
178 * extracts a single named kernel, and applies the specified build options during compilation.
179 *
180 * @param resource the classpath path to the OpenCL source file
181 * @param kernelName the name of the kernel function to extract
182 * @param buildOptions the build options for OpenCL compilation
183 * @return a new program specification with the given resource, kernel, and build options
184 * @throws IllegalArgumentException if resource or kernelName is null or blank
185 */
186 public static Program ofResource(final String resource, final String kernelName, final String buildOptions) {
187 Validate.notBlank(resource);
188 Validate.notBlank(kernelName);
189
190 return ImmutableProgram.builder()
191 .addResources(resource)
192 .addKernelNames(kernelName)
193 .buildOptions(buildOptions)
194 .build();
195 }
196
197 /**
198 * Creates a new builder for constructing complex program specifications.
199 *
200 * <p>The builder provides a fluent interface for creating programs with multiple source files, kernels, and advanced
201 * configuration options.
202 *
203 * @return a new builder instance for creating program specifications
204 */
205 public static ImmutableProgram.Builder builder() {
206 return ImmutableProgram.builder();
207 }
208 }