1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package hat;
27
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.Optional;
31
32 /**
33 * Config bits shared across Java and Native code.
34 *
35 * <p>
36 * After modifying this file, run the following command to sync the corresponding
37 * config with the native side.
38 * </p>
39 *
40 * <p>
41 * <code>
42 * java @.ffisync
43 * </code>
44 * </p>
45 */
46 public class Config {
47
48 public record Bit(int index, int size, String name, String alt, String description) implements Comparable<Bit> {
49 static Bit of(int index, int size, String name, String alt, String description){
50 return new Bit(index,size,name, alt, description);
51 }
52 public static Bit of(int index, String name, String alt, String description){
53 return new Bit(index,1,name, alt,description);
54 }
55
56 public static Bit nextBit(Bit bit, int size, String name, String alt,String description){
57 return new Bit(bit.index+bit.size,size,name, alt, description);
58 }
59 public static Bit nextBit(Bit bit, String name, String alt, String description){
60 return nextBit(bit, 1,name,alt, description);
61 }
62 @Override
63 public int compareTo(Bit bit) {
64 return Integer.compare(index, bit.index);
65 }
66
67 public boolean isBitSet(int bits) {
68 return (mask() & bits) == mask();
69 }
70
71 public boolean isSet(Config config) {
72 return (mask() & config.bits) == mask();
73 }
74
75 public int mask() {
76 return ((1 << size) - 1) << index;
77 }
78
79 public String maskString() {
80 return Integer.toBinaryString(mask());
81 }
82 }
83
84 public static final Bit PLATFORM = Bit.of(0, 3, "PLATFORM","P", "FFI ONLY platform id (0-7)");
85 public static final Bit DEVICE = Bit.nextBit(PLATFORM, 3, "DEVICE","D","FFI ONLY device id (0-7)");
86
87 private static final Bit MINIMIZE_COPIES = Bit.nextBit(DEVICE, "MINIMIZE_COPIES","MC","FFI ONLY Try to minimize copies");
88 public boolean minimizeCopies() {
89 return MINIMIZE_COPIES.isSet(this);
90 }
91
92 private static final Bit TRACE = Bit.nextBit(MINIMIZE_COPIES,"TRACE", "T","FFI ONLY trace code");
93
94 private static final Bit PROFILE = Bit.nextBit(TRACE, "PROFILE", "P","FFI ONLY Turn on profiling");
95
96 private static final Bit SHOW_CODE = Bit.nextBit(PROFILE,"SHOW_CODE","SC","Show generated code (PTX/OpenCL/CUDA)");
97 public boolean showCode() {
98 return SHOW_CODE.isSet(this);
99 }
100
101 private static final Bit SHOW_KERNEL_MODEL = Bit.nextBit(SHOW_CODE,"SHOW_KERNEL_MODEL", "SKM","Show (via OpWriter) Kernel Model");
102 public boolean showKernelModel() {
103 return SHOW_KERNEL_MODEL.isSet(this);
104 }
105
106 private static final Bit SHOW_COMPUTE_MODEL = Bit.nextBit(SHOW_KERNEL_MODEL,"SHOW_COMPUTE_MODEL", "SCM","Show (via OpWriter) Compute Model");
107 public boolean showComputeModel() {
108 return SHOW_COMPUTE_MODEL.isSet(this);
109 }
110
111 private static final Bit SHOW_DEVICE_INFO = Bit.nextBit(SHOW_COMPUTE_MODEL, "SHOW_DEVICE_INFO", "SDI","FFI show platform and device info");
112
113 public static final Bit INFO = Bit.nextBit(SHOW_DEVICE_INFO, "INFO", "I","INFO level logging");
114
115 public static final Bit WARN = Bit.nextBit(INFO, "WARN", "W","WARN(ing) level logging ");
116
117 public static final Bit UNIT = Bit.nextBit(WARN, "UNIT", "U","UNIT test level logging ");
118
119 private static final Bit TRACE_COPIES = Bit.nextBit(UNIT, "TRACE_COPIES", "TC","FFI ONLY trace copies");
120
121 private static final Bit TRACE_SKIPPED_COPIES = Bit.nextBit(TRACE_COPIES,"TRACE_SKIPPED_COPIES", "TSC", "FFI ONLY Trace skipped copies (see MINIMIZE_COPIES) ");
122
123 private static final Bit TRACE_ENQUEUES = Bit.nextBit(TRACE_SKIPPED_COPIES,"TRACE_ENQUEUES","TE", "FFI ONLY trace enqueued tasks");
124
125 private static final Bit TRACE_CALLS= Bit.nextBit(TRACE_ENQUEUES, "TRACE_CALLS", "TCALLS","FFI ONLY trace calls (enter/leave)");
126
127 private static final Bit SHOW_WHY = Bit.nextBit(TRACE_CALLS, "SHOW_WHY", "SW","FFI ONLY show why we decided to copy buffer (H to D)");
128
129 private static final Bit SHOW_STATE = Bit.nextBit(SHOW_WHY, "SHOW_STATE", "SS","Show iface buffer state changes");
130 public boolean showState(){return SHOW_STATE.isSet(this);}
131
132 private static final Bit PTX = Bit.nextBit(SHOW_STATE, "PTX", "PTX","FFI (NVIDIA) ONLY pass PTX rather than C99 CUDA code");
133 public boolean ptx(){return PTX.isSet(this);}
134
135 private static final Bit INTERPRET = Bit.nextBit(PTX, "INTERPRET", "I","Interpret the code model rather than converting to bytecode");
136 public boolean interpret() {
137 return INTERPRET.isSet(this);
138 }
139
140 private static final Bit HEADLESS = Bit.nextBit(INTERPRET, "HEADLESS", "H","Don't show UI");
141 public boolean headless() {
142 return HEADLESS.isSet(this) || Boolean.getBoolean("headless");
143 }
144 public boolean headless(String arg) {
145 return headless() || "--headless".equals(arg);
146 }
147
148 private static final Bit SHOW_LOWERED_KERNEL_MODEL = Bit.nextBit(HEADLESS,"SHOW_LOWERED_KERNEL_MODEL", "SLKM","Show (via OpWriter) Lowered Kernel Model");
149 public boolean showLoweredKernelModel() {
150 return SHOW_LOWERED_KERNEL_MODEL.isSet(this);
151 }
152
153 private static final Bit SHOW_COMPILATION_PHASES = Bit.nextBit(SHOW_LOWERED_KERNEL_MODEL, "SHOW_COMPILATION_PHASES","SCP", "Show HAT compilation phases");
154 public boolean showCompilationPhases() {
155 return SHOW_COMPILATION_PHASES.isSet(this);
156 }
157
158 private static final Bit SHOW_COMPUTE_MODEL_JAVA_CODE = Bit.nextBit(SHOW_COMPILATION_PHASES, "SHOW_COMPUTE_MODEL_JAVA_CODE","SCMJC", "Show java code view of compute model");
159 public boolean showComputeModelJavaCode() {
160 return SHOW_COMPUTE_MODEL_JAVA_CODE.isSet(this);
161 }
162
163 public static final Bit CHECK_SSA_LOWERING = Bit.nextBit(SHOW_COMPUTE_MODEL_JAVA_CODE, "CHECK_SSA_LOWERING","CSSAL", "Verify that code model can be lowered to SSA");
164 public boolean checkSSALowering() {
165 return CHECK_SSA_LOWERING.isSet(this);
166 }
167
168 public static final Bit CUDA_COMPILER_NVCC = Bit.nextBit(CHECK_SSA_LOWERING, "CUDA_NVCC","NVCC", "Select the NVCC CUDA Compiler (Default)");
169 public static final Bit CUDA_COMPILER_NVRTC = Bit.nextBit(CUDA_COMPILER_NVCC, "CUDA_NVRTC","NVRTC", "Select the NVRTC CUDA Compiler");
170
171 public boolean info() {
172 return INFO.isSet(this);
173 }
174
175 public static final List<Bit> bitList = List.of(
176 PLATFORM,
177 DEVICE,
178 MINIMIZE_COPIES,
179 TRACE,
180 PROFILE,
181 SHOW_CODE,
182 SHOW_KERNEL_MODEL,
183 SHOW_COMPUTE_MODEL,
184 SHOW_DEVICE_INFO,
185 INFO,
186 WARN,
187 UNIT,
188 TRACE_COPIES,
189 TRACE_SKIPPED_COPIES,
190 TRACE_ENQUEUES,
191 TRACE_CALLS,
192 SHOW_WHY,
193 SHOW_STATE,
194 PTX,
195 INTERPRET,
196 HEADLESS,
197 SHOW_LOWERED_KERNEL_MODEL,
198 SHOW_COMPILATION_PHASES,
199 SHOW_COMPUTE_MODEL_JAVA_CODE,
200 CHECK_SSA_LOWERING,
201 CUDA_COMPILER_NVCC,
202 CUDA_COMPILER_NVRTC
203 );
204
205 private final int bits;
206
207 public int bits() {
208 return bits;
209 }
210
211 Config(int bits) {
212 this.bits = bits;
213 }
214
215 // These must sync with hat/backends/ffi/shared/include/config.h
216 // We can create the above config by running main() below...
217 public static Config fromEnvOrProperty() {
218 if (System.getenv("HAT") instanceof String opts) {
219 return fromSpec(opts);
220 } else if (System.getProperty("HAT") instanceof String opts) {
221 return fromSpec(opts);
222 } else {
223 return fromSpec("");
224 }
225 }
226
227 public static Config fromIntBits(int bits) {
228 return new Config(bits);
229 }
230
231 record BitValue(Bit bit, int value){}
232
233 public static Config fromSpec(String spec) {
234 Optional<Config> returnValue = Optional.of(Config.fromIntBits(0));
235 if (spec == null || spec.isEmpty()) {
236 // default is good
237 } else if (spec.equals("HELP")) {
238 bitList.forEach(bit -> IO.println(bit.name + "/" + bit.alt + " ".repeat(40 - (bit.name.length() + bit.alt.length())) + (bit.index < 10 ? " " : "") + bit.index + ((bit.size > 1) ? "-" + (bit.index + bit.size - 1) : " ") + " " + bit.description));
239 if (spec.equals("HELP")) {
240 System.exit(0);
241 }
242 } else if (spec.contains(",")) {
243 returnValue = Arrays.stream(spec.split(",")).map(Config::fromSpec).reduce((lhs, rhs) -> Config.fromIntBits(lhs.bits() | rhs.bits()));
244 } else if (!spec.contains(":")) {
245 returnValue = bitList.stream().filter(bit -> bit.name().equals(spec) || bit.alt().equals(spec)).findFirst().map(b -> fromIntBits(b.mask()));
246 } else {
247 var split = spec.split(":");
248 if (split.length == 2) {
249 var optBit = bitList.stream().filter(bit -> bit.name().equals(split[0]) || bit.alt().equals(split[0])).findFirst();
250 if (optBit.isPresent()) {
251 int value = Integer.parseInt(split[1]);
252 // Don't allow devices or platforms outside the supported range
253 if ((optBit.get().alt.equals("P") || optBit.get().alt.equals("D")) && (value < 0 || value > 7)) {
254 throw new IllegalArgumentException("Invalid value for " + split[0] + ":" + split[1]);
255 }
256 var bv = new BitValue(optBit.get(), Integer.parseInt(split[1]));
257 var bitz = bv.value << bv.bit().index();
258 returnValue = Optional.of(fromIntBits(bitz));
259 }
260 }
261 }
262 if (returnValue.isPresent()) {
263 return returnValue.get();
264 } else {
265 IO.println("Unexpected spec '" + spec + "'");
266 System.exit(1);
267 }
268 return null;
269 }
270
271 @Override
272 public String toString() {
273 StringBuilder builder = new StringBuilder();
274 for (Bit bit:bitList){
275 if (bit.isBitSet(bits)) {
276 if (!builder.isEmpty()) {
277 builder.append("|");
278 }
279 builder.append(bit.name());
280 }
281 }
282 return builder.toString();
283 }
284
285 public static void main() {
286 bitList.forEach(b-> System.out.printf("%30s MASK= %32s\n", b.name, b.maskString()));
287 }
288 }