1 # Building HAT
  2 
  3 ----
  4 
  5 * [Contents](hat-00.md)
  6 * House Keeping
  7     * [Project Layout](hat-01-01-project-layout.md)
  8     * [Building Babylon](hat-01-02-building-babylon.md)
  9     * [Building HAT](hat-01-03-building-hat.md)
 10       * [Enabling the CUDA Backend](hat-01-05-building-hat-for-cuda.md)
 11 * Programming Model
 12     * [Programming Model](hat-03-programming-model.md)
 13 * Interface Mapping
 14     * [Interface Mapping Overview](hat-04-01-interface-mapping.md)
 15     * [Cascade Interface Mapping](hat-04-02-cascade-interface-mapping.md)
 16 * Implementation Detail
 17     * [Walkthrough Of Accelerator.compute()](hat-accelerator-compute.md)
 18     * [How we minimize buffer transfers](hat-minimizing-buffer-transfers.md)
 19 
 20 ---
 21 
 22 # Building HAT with Script
 23 
 24 We initially used maven and cmake to build hat.  If you feel more comfortable
 25 with maven consider [building with maven and cmake](hat-01-03-building-hat-with-maven.md)
 26 but it is possible that maven support will be removed if the `Script` approach takes off.
 27 
 28 ## Dependencies
 29 
 30 Before we start to build HAT we will need `cmake` and `jextract` installed.
 31 
 32 You can download jextract from [here](https://jdk.java.net/jextract/)
 33 
 34 Use `sudo apt` on Linux or `brew install`.
 35 
 36 ```bash
 37 sudo apt install cmake
 38 
 39 ```
 40 
 41 ```bash
 42 brew install cmake
 43 ```
 44 
 45 
 46 You will also need a Babylon JDK built (the one we built [here](hat-01-02-building-babylon.md))
 47 
 48 
 49 ## Setting your PATH variable
 50 
 51 To build HAT we will need `JAVA_HOME` to point to our prebuilt babylon jdk
 52 
 53 I suggest you also create a `JEXTRACT_HOME` var to point to the location where you placed JEXTRACT)
 54 
 55 In my case
 56 ```
 57 export JEXTRACT_HOME=/Users/me/jextract-22
 58 ```
 59 
 60 Make sure also that `cmake` in in your PATH
 61 
 62 ## ./env.bash
 63 
 64 Thankfully just sourcing the top level `env.bash` script should then be able to set up your PATH for you.
 65 
 66 It should detect the arch type (AARCH64 or X86_46) and
 67 select the correct relative parent dir for your BABYLON_JDK and inject that dir in your PATH.
 68 
 69 It should also add jextract to your PATH (based on the value you set above for JEXTRACT_HOME)
 70 
 71 
 72 
 73 ```bash
 74 cd hat
 75 export JEXTRACT_HOME=/Users/me/jextract-22
 76 . ./env.bash
 77 echo ${JAVA_HOME}
 78 /Users/me/github/babylon/hat/../build/macosx-aarch64-server-release/jdk
 79 echo ${PATH}
 80 /Users/me/github/babylon/hat/../build/macosx-aarch64-server-release/jdk/bin:/Users/me/jextract-22/bin:/usr/local/bin:......
 81 ```
 82 
 83 ## Building using bld
 84 
 85 To build hat artifacts (hat jar + backends and examples)
 86 ```bash
 87 java @hat/bld
 88 ```
 89 
 90 This places build artifacts in the `build` and `stages` dirs
 91 
 92 ```bash
 93 cd hat
 94 . ./env.bash
 95 java @hat/bld
 96 ls build
 97 hat-1.0.jar                         hat-example-heal-1.0.jar        libptx_backend.dylib
 98 hat-backend-ffi-cuda-1.0.jar        hat-example-mandel-1.0.jar      libspirv_backend.dylib
 99 hat-backend-ffi-mock-1.0.jar        hat-example-squares-1.0.jar     mock_info
100 hat-backend-ffi-opencl-1.0.jar      hat-example-view-1.0.jar        opencl_info
101 hat-backend-ffi-ptx-1.0.jar         hat-example-violajones-1.0.jar  ptx_info
102 hat-backend-ffi-spirv-1.0.jar       libmock_backend.dylib           spirv_info
103 hat-example-experiments-1.0.jar     libopencl_backend.dylib
104 ls stage
105 opencl_jextracted    opengl_jextracted
106 ```
107 
108 `bld` relies on cmake to build native code for backends, so if cmake finds OpenCL libs/headers, you will see libopencl_backend (.so or .dylib) in the build dir, if cmake finds CUDA you will see libcuda_backend(.so or .dylib)
109 
110 We have another script called `sanity` which will check all  .md/.java/.cpp/.h for tabs, lines that end with whitespace
111 or files without appropriate licence headers
112 
113 This is run using
114 
115 ```
116 java @hat/sanity
117 ```
118 
119 
120 ## Running an example
121 
122 To run a HAT example we can run from the artifacts in `build` dir
123 
124 ```bash
125 ${JAVA_HOME}/bin/java \
126    --add-modules jdk.incubator.code --enable-preview --enable-native-access=ALL-UNNAMED \
127    --class-path build/core-1.0.jar:build/hat-backend-ffi-shared-1.0.jar:build/hat-backend-ffi-opencl-1.0.jar:build/hat-example-mandel-1.0.jar \
128    --add-exports=java.base/jdk.internal=ALL-UNNAMED \
129    -Djava.library.path=build\
130    mandel.Main
131 ```
132 
133 The `hat/run.java` script can also be used which simply needs the backend
134 name `ffi-opencl|ffi-java|ffi-cuda|ffi-ptx|ffi-mock` and the package name `mandel`
135 
136 ```bash
137 java @hat/run ffi-opencl mandel
138 ```
139 
140 If you pass `headless` as the first arg
141 
142 ```bash
143 java @hat/run headless ffi-opencl mandel
144 ```
145 
146 This sets `-Dheadless=true` and passes '--headless' to the example.  Some examples can use this to avoid launching UI.
147 
148 
149 # More Bld info
150 `hat/Script.java` is an evolving set of static methods and types required (so far.. ;) )
151 to be able to build HAT, hat backends and examples via the `bld` script
152 
153 We rely on java's ability to launch java source directly (without needing to javac first)
154 
155 * [JEP 458: Launch Multi-File Source-Code Program](https://openjdk.org/jeps/458)
156 * [JEP 330: Launch Single-File Source-Code Programs](https://openjdk.org/jeps/330)
157 
158 The `hat/bld.java` script (really java source) can be run like this
159 
160 ```bash
161 java --add-modules jdk.incubator.code --enable-preview --source 26 hat/bld.java
162 ```
163 
164 In our case the  magic is under the `hat`subdir
165 
166 We also have a handy `hat/XXXX` which allows us to avoid specifying common args `--enable-preview --source 26` eash time we launch a script
167 
168 ```
169 hat
170 ├── hat
171 |   ├── Script.java
172 |   ├── sanity      (the args for sanity.java)  "--enable-preview --source 26 sanity"
173 |   |-- sanity.java (the script)
174 |   ├── run         (the args for sanity.java)  "--enable-preview --source 26 hatrun"
175 |   |-- run.java    (the script)
176 |   ├── bld         (the args for bld.java)      "--enable-preview --source 26 bld"
177 |   ├── bld.java    (the script)
178 
179 ```
180 
181 For example
182 ```bash
183 java @hat/bld
184 ```
185 
186 Is just a shortcut for
187 ```bash
188 java --add-modules jdk.incubator.code --enable-preview --source 26 hat/bld.java
189 ```
190 
191 
192 ----
193 ### HAT runtime environment variable.
194 
195 During ffi-backend development we added some useful flags to pass to native code to allow us to trace calls, inject logging, control options.
196 
197 These should be considered just development flags.
198 
199 At runtime the ffi-backends all communicate from the java side to the native side via a 32 bit 'config' int.
200 
201 The Java side class [hat.backend.ffi.Config](https://github.com/openjdk/babylon/blob/code-reflection/hat/backends/ffi/shared/src/main/java/hat/backend/ffi/Config.java)
202 
203 Is initialized from an environment variable `HAT` at runtime
204 
205 So for example when we launch
206 ```bash
207 java @hat/run ffi-opencl heal
208 ```
209 
210 We can pass config info to `HAT` via either `-DHAT=xxx` or via the `HAT` ENV variable.
211 
212 So for example to get HAT to dump the text form of the kernel code models.
213 
214 ```
215 HAT=INFO,SHOW_KERNEL_MODEL java @hat/run ffi-opencl heal
216 ```
217 
218 Or to show generated opencl or cuda code
219 ```
220 HAT=INFO,SHOW_CODE java @hat/run ffi-opencl heal
221 ```
222 
223 This is particularly useful for selecting PLATFORM + DEVICE if you have multiple GPU devices.
224 
225 Here we select DEVICE 0 on PLATFORM 0 (actually the default)
226 ```
227 HAT=INFO,PLATFORM:0,DEVICE:0,SHOW_CODE ...
228 ```
229 or for DEVICE 1 on PLATFORM 1
230 ```
231 HAT=INFO,PLATFORM:1,DEVICE:1,SHOW_CODE ...
232 ```
233 
234 No the platform and device id's are 4 bits. This probably works for development, but we will need a more expressive way of capturing this via the accelerator selection.
235 
236 This just allows us to test without code changes.
237 
238 To keep he java code and the native code in sync.  The `main` method at the end of
239  [hat.backend.ffi.Config](https://github.com/openjdk/babylon/blob/code-reflection/hat/backends/ffi/shared/src/main/java/hat/backend/ffi/Config.java)
240 is actually used to create the C99 header for Cuda and OpenCL ffi-backends.
241 
242 So whenever we change the Java config class we should run the main method to generate the header.   This is not really robust, (but proved way better than trying to remember for all backends) but you need to know, if you add move config bits to the Java side.
243 
244 The Main method uses a variant of the code builders used for C99 style code (CUDA/OpenCL) to generate the config.h header.
245 
246 This is how we keep the ffi based backends in sync
247 
248 Some more useful `config bits`
249 
250 ```
251 HAT=PTX java @hat/run ffi-cuda ....
252 ```
253 Sends PTX generated by our prototype PTX generator to the backend (for CUDA) rather than C99 code.
254 
255 ```
256 HAT=INFO java @hat/run ....
257 ```
258 
259 Will dump all of the `config bits` from the native side.
260 
261 At present this yields
262 ```
263 native minimizeCopies 0
264 native trace 0
265 native profile 0
266 native showCode 0
267 native showKernelModel 0
268 native showComputeModel 0
269 native info 1
270 native traceCopies 0
271 native traceSkippedCopies 0
272 native traceEnqueues 0
273 native traceCalls 0
274 native showWhy 0
275 native showState 0
276 native ptx 0
277 native interpret 0
278 ```
279 Generally the flags all represent single bits (except PLATFORM:n and DEVICE:n) and are set using comma separated uppercase+underscore string forms.
280 
281 
282 So to experiment with `minimizeCopies` and to  `showCode` we set `HAT=MINIMIZE_COPIES,SHOW_CODE`