1 /* vim: set ft=java:
  2  * Copyright (c) 2024-2026, 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 import static java.lang.IO.print;
 27 import static java.lang.IO.println;
 28 import java.util.regex.Matcher;
 29 import java.util.regex.Pattern;
 30 
 31 class Config {
 32     boolean headless = false;
 33     boolean verbose = false;
 34     boolean startOnFirstThread = false;
 35     boolean justShowCommandline = false;
 36     boolean runSuite = false;
 37     String backendName = null;
 38     Script.JarFile backendJar = null;
 39     String testName = null;
 40     String examplePackageName = null;
 41     String testMainClassName = null;
 42     Script.JarFile exampleJar = null;
 43     List<Script.ClassPathEntryProvider> classpath = new ArrayList<>();
 44     List<String> vmargs = new ArrayList<>();
 45     List<String> appargs = new ArrayList<>();
 46 
 47     Config(Script.BuildDir buildDir, String[] args) {
 48 
 49         var testJARFile = buildDir.jarFile("hat-tests-1.0.jar");
 50         if (testJARFile.exists()) {
 51             testMainClassName = "hat.test.engine.HATTestEngine";
 52             exampleJar = testJARFile;
 53             if (exampleJar.exists()) {
 54                 classpath.add(exampleJar);
 55             } else {
 56                 System.err.println("Cannot find example jar at " + testMainClassName);
 57             }
 58         }
 59 
 60         classpath.add(buildDir.jarFile("hat-tests-1.0.jar"));
 61         classpath.add(buildDir.jarFile("hat-core-1.0.jar"));
 62         classpath.add(buildDir.jarFile("hat-example-shared-1.0.jar"));
 63 
 64         for (int arg = 0; arg < args.length; arg++) {
 65 
 66             if (args[arg].equals("suite")) {
 67                 runSuite = true;
 68             } else if (args[arg].startsWith("ffi-")) {
 69                 backendName = args[arg];
 70                 backendJar = buildDir.jarFile("hat-backend-" + backendName + "-1.0.jar");
 71                 classpath.add(buildDir.jarFile("hat-backend-ffi-shared-1.0.jar"));
 72                 classpath.add(backendJar);
 73             } else if (args[arg].startsWith("java-")) {
 74                 backendName = args[arg];
 75                 backendJar = buildDir.jarFile("hat-backend-" + backendName + "-1.0.jar");
 76                 classpath.add(backendJar);
 77             } else {
 78                 switch (args[arg]) {
 79                     case "headless" -> headless = true;
 80                     case "verbose" -> verbose = true;
 81                     case "justShowCommandLine" -> justShowCommandline = true;
 82                     case "startOnFirstThread" -> startOnFirstThread = true;
 83                     default -> {
 84                         this.appargs.add(args[arg]);
 85                     }
 86                 }
 87             }
 88         }
 89     }
 90 }
 91 
 92 class Stats {
 93     int passed = 0;
 94     int failed = 0;
 95     int unsupported = 0;
 96     int precisionErrors = 0;
 97     public void incrementPassed(int val) { this.passed += val; }
 98     public void incrementFailed(int fail) {
 99         this.failed += fail;
100     }
101     public void incrementUnsupported(int unsupporeted) {
102         this.unsupported += unsupporeted;
103     }
104     public void incrementPrecisionErrors(int precisionErrors) {
105         this.precisionErrors += precisionErrors;
106     }
107 
108     public int getPassed() {
109         return passed;
110     }
111     public int getFailed() {
112         return failed;
113     }
114     public int getUnsupported() {
115         return unsupported;
116     }
117     public int getPrecisionErrors { return precisionErrors }
118 
119     @Override
120     public String toString() {
121         return String.format("Global passed: %d, failed: %d, unsupported: %d, precision-errors: %d, pass-rate: %.2f%%",
122                 passed, failed, unsupported, precisionErrors, ((float)(passed * 100 / (passed + failed + unsupported + precisionErrors))));
123     }
124 }
125 
126 void main(String[] argv) {
127     var usage = """
128               usage:
129                 java @hat/test [backend] class
130                     backend   : opencl|cuda
131 
132                 examples:
133                    java @hat/test suite ffi-opencl
134                    java @hat/test ffi-opencl class#method
135                    java @hat/test suite ffi-cuda
136                    java @hat/test ffi-cuda class#method
137             """;
138 
139     var hatDir = Script.DirEntry.current();
140     var buildDir = hatDir.existingBuildDir("build");
141 
142     Config config = new Config(buildDir, argv);
143 
144     if (config.classpath.isEmpty()) {
145         println("Classpath is empty!");
146     } else if (config.backendJar == null || !config.backendJar.exists()) {
147         println("No backend !");
148     } else if (!config.exampleJar.exists()) {
149         println("No example !");
150     } else {
151         var extraction_opencl_jar = buildDir.jarFile("hat-extraction-opencl-1.0.jar");
152         var extraction_opengl_jar = buildDir.jarFile("hat-extraction-opengl-1.0.jar");
153         var wrap_shared_jar = buildDir.jarFile("hat-wrap-shared-1.0.jar");
154         var wrap_opencl_jar = buildDir.jarFile("hat-wrap-opencl-1.0.jar");
155         var wrap_opengl_jar = buildDir.jarFile("hat-wrap-opengl-1.0.jar");
156         switch (config.backendName) {
157             default -> {
158             }
159         }
160     }
161 
162     // Remove the previous report file:
163     Path file = Paths.get("test_report.txt");
164     try {
165         Files.deleteIfExists(file);
166     } catch (IOException e) {
167         e.printStackTrace();
168     }
169 
170     if (config.runSuite) {
171 
172         String[] suite = new String[] {
173                 "hat.test.TestMatMul",
174                 "hat.test.TestArrays",
175                 "hat.test.TestMandel",
176                 "hat.test.TestLocal",
177                 "hat.test.TestReductions",
178                 "hat.test.TestPrivate",
179                 "hat.test.TestParenthesis",
180                 "hat.test.TestConstants",
181                 "hat.test.TestBlackscholes",
182                 "hat.test.TestNbody",
183                 "hat.test.TestArrayView",
184                 "hat.test.TestVectorTypes",
185                 "hat.test.TestF16Type",
186                 "hat.test.TestFloat2",
187                 "hat.test.TestBFloat16Type",
188                 "hat.test.TestDeviceType",
189                 "hat.test.TestVecorArrayView",
190                 "hat.test.TestNumBlocks"
191         };
192 
193         // Test the whole suite
194         for (String testClass : suite) {
195             Script.java(java -> java
196                     .enable_preview()
197                     .verbose(true)
198                     .enable_native_access("ALL-UNNAMED")
199                     .add_modules("jdk.incubator.code")
200                     .library_path(buildDir)
201                     .when(config.headless, Script.JavaBuilder::headless)
202                     .when(config.startOnFirstThread, Script.JavaBuilder::start_on_first_thread)
203                     .class_path(config.classpath)
204                     .vmargs(config.vmargs)
205                     .main_class(config.testMainClassName)
206                     .args(testClass)
207                     .justShowCommandline(config.justShowCommandline));
208         }
209 
210         // Final report
211         String regex = "passed: (\\d+), failed: (\\d+), unsupported: (\\d+)";
212         Pattern pattern = Pattern.compile(regex);
213         Stats stats = new Stats();
214 
215         System.out.println("\n\n************************************************");
216         System.out.println("                 HAT Test Report ");
217         System.out.println("************************************************");
218         try {
219             List<String> lines = Files.readAllLines(file);
220             for (String line : lines) {
221                 System.out.println(line);
222 
223                 Matcher matcher = pattern.matcher(line);
224                 if (matcher.find()) {
225                     int passed = Integer.parseInt(matcher.group(1));
226                     int fail = Integer.parseInt(matcher.group(2));
227                     int unsupported = Integer.parseInt(matcher.group(3));
228                     int precisionErrors = Integer.parseInt(matcher.group(4));
229                     stats.incrementPassed(passed);
230                     stats.incrementFailed(fail);
231                     stats.incrementUnsupported(unsupported);
232                     stats.incrementPrecisionErrors(precisionErrors);
233                 }
234             }
235         } catch (IOException e) {
236             e.printStackTrace();
237         }
238         System.out.println(stats);
239         if (stats.failed > 0) {
240             System.exit(-1);
241         } else {
242             System.exit(0);
243         }
244     } else {
245         // A single command for a specific class/method
246         Script.java(java -> java
247                 .enable_preview()
248                 .verbose(true)
249                 .enable_native_access("ALL-UNNAMED")
250                 .add_modules("jdk.incubator.code")
251                 .library_path(buildDir)
252                 .when(config.headless, Script.JavaBuilder::headless)
253                 .when(config.startOnFirstThread, Script.JavaBuilder::start_on_first_thread)
254                 .class_path(config.classpath)
255                 .vmargs(config.vmargs)
256                 .main_class(config.testMainClassName)
257                 .args(config.appargs)
258                 .justShowCommandline(config.justShowCommandline));
259     }
260 }