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