Skip to content

Commit 7ed9fd3

Browse files
authored
Merge pull request #5 from Hellblazer/feature/build-options-support
Add build options support to ComputeKernel interface
2 parents 57432b4 + 04ceffa commit 7ed9fd3

File tree

3 files changed

+627
-3
lines changed

3 files changed

+627
-3
lines changed

resource/src/main/java/com/hellblazer/luciferase/resource/compute/ComputeKernel.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,71 @@ public interface ComputeKernel extends AutoCloseable {
3232
*/
3333
void compile(String source, String entryPoint) throws KernelCompilationException;
3434

35+
/**
36+
* Compile the kernel from source code with build options for GPU auto-tuning.
37+
*
38+
* <p>Build options enable runtime kernel customization through preprocessor defines
39+
* and compiler flags, essential for GPU auto-tuning and performance optimization.
40+
*
41+
* <h3>Build Options Examples:</h3>
42+
* <ul>
43+
* <li><b>Preprocessor Defines:</b> {@code "-DBLOCK_SIZE=256 -DENABLE_SHARED_MEMORY=1"}</li>
44+
* <li><b>Compiler Flags:</b> {@code "-cl-fast-relaxed-math -cl-mad-enable"}</li>
45+
* <li><b>Warning Control:</b> {@code "-Werror"} (treat warnings as errors)</li>
46+
* <li><b>Vendor-Specific:</b> {@code "-D__CUDA_ARCH__=700"} (NVIDIA), {@code "-D__GCN__"} (AMD)</li>
47+
* </ul>
48+
*
49+
* <h3>Use Cases:</h3>
50+
* <ul>
51+
* <li>Runtime work group size tuning: {@code "-DWORK_GROUP_SIZE=256"}</li>
52+
* <li>Feature toggling: {@code "-DENABLE_FEATURE=1"}</li>
53+
* <li>Math optimizations: {@code "-cl-fast-relaxed-math"}</li>
54+
* <li>Architecture-specific tuning: {@code "-D__GCN_REV__=2"}</li>
55+
* </ul>
56+
*
57+
* @param source Kernel source code (Metal or OpenCL)
58+
* @param entryPoint Kernel entry point function name
59+
* @param buildOptions Compiler flags and preprocessor defines (null or empty for defaults)
60+
* @throws KernelCompilationException if compilation fails
61+
* @see #recompile(String, String, String)
62+
*/
63+
default void compile(String source, String entryPoint, String buildOptions)
64+
throws KernelCompilationException {
65+
throw new UnsupportedOperationException("Build options not supported by this compute backend");
66+
}
67+
68+
/**
69+
* Recompile an already-compiled kernel with different build options.
70+
*
71+
* <p>Enables runtime GPU auto-tuning by recompiling kernels with different optimization
72+
* parameters without clearing existing kernel state. Useful for performance experiments
73+
* and adaptive optimization strategies.
74+
*
75+
* <h3>Recompilation Workflow:</h3>
76+
* <pre>{@code
77+
* // Initial compilation
78+
* kernel.compile(source, "myKernel", "-DBLOCK_SIZE=128");
79+
* kernel.execute(globalSize); // Test performance
80+
*
81+
* // Recompile with different block size
82+
* kernel.recompile(source, "myKernel", "-DBLOCK_SIZE=256");
83+
* kernel.execute(globalSize); // Compare performance
84+
* }</pre>
85+
*
86+
* <p><b>Note:</b> Recompilation creates a fresh kernel. The old kernel reference remains
87+
* valid until explicitly closed, allowing multiple kernel variants to coexist.
88+
*
89+
* @param source Kernel source code (must match original source for consistency)
90+
* @param entryPoint Kernel entry point function name
91+
* @param buildOptions New compiler flags and preprocessor defines
92+
* @throws KernelCompilationException if recompilation fails
93+
* @see #compile(String, String, String)
94+
*/
95+
default void recompile(String source, String entryPoint, String buildOptions)
96+
throws KernelCompilationException {
97+
throw new UnsupportedOperationException("Recompilation not supported by this compute backend");
98+
}
99+
35100
/**
36101
* Set a buffer argument for the kernel.
37102
*

resource/src/main/java/com/hellblazer/luciferase/resource/compute/opencl/OpenCLKernel.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,21 +82,49 @@ private OpenCLKernel(String name, long context, long commandQueue, long device)
8282

8383
@Override
8484
public void compile(String source, String entryPoint) throws KernelCompilationException {
85+
compile(source, entryPoint, null);
86+
}
87+
88+
@Override
89+
public void compile(String source, String entryPoint, String buildOptions) throws KernelCompilationException {
8590
checkNotClosed();
8691
if (compiled.get()) {
8792
throw new KernelCompilationException("Kernel already compiled");
8893
}
8994

95+
compileInternal(source, entryPoint, buildOptions);
96+
}
97+
98+
@Override
99+
public void recompile(String source, String entryPoint, String buildOptions) throws KernelCompilationException {
100+
checkNotClosed();
101+
102+
// Clean up old kernel and program
103+
cleanup();
104+
105+
// Compile fresh kernel with new build options
106+
compileInternal(source, entryPoint, buildOptions);
107+
}
108+
109+
/**
110+
* Internal compilation method shared by compile() and recompile().
111+
*/
112+
private void compileInternal(String source, String entryPoint, String buildOptions)
113+
throws KernelCompilationException {
114+
90115
try (var stack = stackPush()) {
91116
// Create program from source
92117
var errcode = stack.mallocInt(1);
93118
program = clCreateProgramWithSource(context, source, errcode);
94119
checkCLError(errcode.get(0), "Failed to create OpenCL program");
95120

96-
// Build program for specific device
121+
// Prepare build options (null and empty are treated as no options)
122+
var options = (buildOptions != null && !buildOptions.isEmpty()) ? buildOptions : "";
123+
124+
// Build program for specific device with build options
97125
var devices = stack.mallocPointer(1);
98126
devices.put(0, device);
99-
var buildStatus = clBuildProgram(program, devices, "", null, NULL);
127+
var buildStatus = clBuildProgram(program, devices, options, null, NULL);
100128
if (buildStatus != CL_SUCCESS) {
101129
// Get build log
102130
var logSize = stack.mallocPointer(1);
@@ -122,7 +150,12 @@ public void compile(String source, String entryPoint) throws KernelCompilationEx
122150
checkCLError(errcode.get(0), "Failed to create OpenCL kernel: " + entryPoint);
123151

124152
compiled.set(true);
125-
log.debug("Compiled OpenCL kernel: {} (entry point: {})", name, entryPoint);
153+
if (buildOptions != null && !buildOptions.isEmpty()) {
154+
log.debug("Compiled OpenCL kernel: {} (entry point: {}, options: {})",
155+
name, entryPoint, buildOptions);
156+
} else {
157+
log.debug("Compiled OpenCL kernel: {} (entry point: {})", name, entryPoint);
158+
}
126159

127160
} catch (Exception e) {
128161
cleanup();

0 commit comments

Comments
 (0)