1 # Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 #
4 # This code is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License version 2 only, as
6 # published by the Free Software Foundation.
7 #
8 # This code is distributed in the hope that it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 # version 2 for more details (a copy is included in the LICENSE file that
12 # accompanied this code).
13 #
14 # You should have received a copy of the GNU General Public License version
15 # 2 along with this work; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 #
18 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 # or visit www.oracle.com if you need additional information or have any
20 # questions.
21
22 #======================================================================
23 # Regression test to run javac with premain prototype, to test the CDS and AOT changes.
24 #
25 # QUICK START:
26 # bash javac-test.sh -n $JAVA
27 #
28 # This shows you all the 5 steps for using the premain prototype:
29 #
30 # (STEP 1 of 5) Dump javac.classlist (skipped)
31 # (STEP 2 of 5) Create Static javac-static.jsa (skipped)
32 # (STEP 3 of 4) Run with javac-static.jsa and dump profile in javac-dynamic.jsa (With Training Data Replay) (skipped)
33 # (STEP 4 of 4) Run with javac-dynamic.jsa and generate AOT code (skipped)
34 # (STEP 5 of 5) Final production run: with javac-dynamic.jsa and load AOT code (skipped)
35 #
36 # bash javac-test.sh $JAVA
37 # This runs all the above 5 steps
38 #======================================================================
39
40 # Usage: bash javac-test.sh $OPTS $JAVA
41 # bash javac-test.sh $OPTS $JAVA $JVMARGS
42 #
43 # $JAVA must be from inside your JDK build dir. E.g., /your/build/dir/images/jdk/bin/java
44 #
45 # $OPTS is optional. Examples:
46 #
47 # - Don't run any tests, just print the command-lines
48 # bash cds-test.sh -n $JAVA
49 #
50 # - Just run test #4
51 # bash cds-test.sh -r 4 $JAVA
52 #
53 # - Run test 5, enable the JIT compile log, and loop for 10000 iterations. Also pass -Xmx16g to the JVM.
54 # bash cds-test.sh -r 5 -lcomp -l 10000 $JAVA -Xmx16g
55 #
56 # See the "while" loop below for all available options
57
58 MYDIR=$(cd $(dirname $0); pwd)
59 echo script is installed at $MYDIR
60
61 LIMIT=
62 QUIET=
63 LOOPS=100
64 EXTRA_ARGS=
65 EXIT_WHEN_FAIL=0
66
67 while true; do
68 if [[ $1 = "-lcomp" ]]; then
69 # Log compiler
70 EXTRA_ARGS="$EXTRA_ARGS -XX:+PrintCompilation"
71 shift
72 elif [[ $1 = "-lsc" ]]; then
73 # Log shared code
74 EXTRA_ARGS="$EXTRA_ARGS -Xlog:aot+codecache -Xlog:aot+codecache+nmethod"
75 shift
76 elif [[ $1 = "-r" ]]; then
77 # Limit the run to a single test case
78 LIMIT=$2
79 shift
80 shift
81 elif [[ $1 = "-l" ]]; then
82 # Number of loops for JavacBench
83 LOOPS=$2
84 shift
85 shift
86 elif [[ $1 = "-n" ]]; then
87 # Don't run any test cases, just print their help message and command line
88 LIMIT=0
89 shift
90 elif [[ $1 = "-f" ]]; then
91 # Exit the script with exit code 1 as soon as a test fails
92 EXIT_WHEN_FAIL=1
93 shift
94 elif [[ $1 = "-q" ]]; then
95 # Don't print the help messages and command line of test cases that are skipped
96 QUIET=1
97 shift
98 elif [[ $1 = "-all" ]]; then
99 # Run all test cases (that are not included in the 5 steps)"
100 # If this flag is NOT specified, only the tests with STEP in their description will be executed.
101 DOALL=1
102 shift
103 else
104 break
105 fi
106 done
107
108 JVM=$1
109
110 echo JVM=$JVM
111
112 JSA_SUFFIX=-$JVM
113
114 # Ioi-specific
115 if test "$TESTBED" != ""; then
116 IOI_PREFIX=$(cd $TESTBED/../..; pwd)
117 fi
118
119 if test "$JVM" = "p"; then
120 # Ioi-specific
121 PRODUCT_BLD=${IOI_PREFIX}
122 IOI_TEST_VM=${IOI_PREFIX}-product/images/jdk
123 elif test "$JVM" = "d"; then
124 PRODUCT_BLD=${IOI_PREFIX}
125 IOI_TEST_VM=${IOI_PREFIX}-debug/images/jdk
126 elif test "$JVM" = "fd"; then
127 PRODUCT_BLD=${IOI_PREFIX}
128 IOI_TEST_VM=${IOI_PREFIX}-fastdebug/images/jdk
129 elif [[ ${JVM}XX =~ /images/jdk/bin/javaXX ]]; then
130 PRODUCT_BLD=$(cd $(dirname $JVM)/../../..; pwd);
131 JSA_SUFFIX=
132 else
133 echo "Please specify the location of the JVM (must be in your /build/dir/images/jdk/bin)"
134 exit 1
135 fi
136
137 JVM_AND_ARGS=$@
138 TEST_NUM=0
139
140 function test-info () {
141 if test "$DOALL" != "1"; then
142 if [[ "$@" =~ STEP ]] ; then
143 true
144 else
145 return 1
146 fi
147 fi
148
149 TEST_NUM=$(expr $TEST_NUM + 1)
150 declare -gA infos
151 declare -gA cmds
152 cmds[$TEST_NUM]=$CMD
153 infos[$TEST_NUM]=$*
154 local SKIPPED=""
155 if test "$LIMIT" != "" && test "$LIMIT" != "$TEST_NUM"; then
156 SKIPPED=" (skipped)"
157 fi
158 if test "$QUIET" = ""; then
159 echo ======================================================================
160 echo "Test $TEST_NUM $*$SKIPPED"
161 echo $CMD
162 fi
163 if test "$SKIPPED" != ""; then
164 return 1
165 else
166 return 0
167 fi
168 }
169
170 function record_success () {
171 somepassed=1
172 declare -gA status
173 status[$TEST_NUM]=OK
174 echo "RESULT: $TEST_NUM = OK"
175 }
176
177 function record_failure () {
178 somefailed=1
179 declare -gA status
180 status[$TEST_NUM]=FAILED
181 echo "RESULT: $TEST_NUM = FAILED"
182 if test "$EXIT_WHEN_FAIL" = "1"; then
183 touch fail-stop.txt
184 exit 1
185 fi
186 }
187
188 cd $MYDIR
189
190 if test ! -f JavacBench.jar; then
191 cat > JavacBench.java <<EOF
192 //this file is auto-generated. Do not add to source control and do not edit.
193 //import org.openjdk.jmh.annotations.*;
194
195 import javax.tools.*;
196 import java.io.*;
197 import java.net.URI;
198 import java.util.*;
199
200 //@State(Scope.Benchmark)
201 public class JavacBench {
202 static class ClassFile extends SimpleJavaFileObject {
203 private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
204 protected ClassFile(String name) {
205 super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);
206 }
207 @Override
208 public ByteArrayOutputStream openOutputStream() { return this.baos; }
209 byte[] toByteArray() { return baos.toByteArray(); }
210 }
211 static class FileManager extends ForwardingJavaFileManager<JavaFileManager> {
212 private Map<String, ClassFile> classesMap = new HashMap<String, ClassFile>();
213 protected FileManager(JavaFileManager fileManager) {
214 super(fileManager);
215 }
216 @Override
217 public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) {
218 ClassFile classFile = new ClassFile(name);
219 classesMap.put(name, classFile);
220 return classFile;
221 }
222 public Map<String, byte[]> getByteCode() {
223 Map<String, byte[]> result = new HashMap<>();
224 for (Map.Entry<String, ClassFile> entry : classesMap.entrySet()) {
225 result.put(entry.getKey(), entry.getValue().toByteArray());
226 }
227 return result;
228 }
229 }
230 static class SourceFile extends SimpleJavaFileObject {
231 private CharSequence sourceCode;
232 public SourceFile(String name, CharSequence sourceCode) {
233 super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
234 this.sourceCode = sourceCode;
235 }
236 @Override
237 public CharSequence getCharContent(boolean ignore) {
238 return this.sourceCode;
239 }
240 }
241
242 public Object compile(int count) {
243 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
244 DiagnosticCollector<JavaFileObject> ds = new DiagnosticCollector<>();
245 Collection<SourceFile> sourceFiles = sources10k.subList(0, count);
246
247 try (FileManager fileManager = new FileManager(compiler.getStandardFileManager(ds, null, null))) {
248 JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, sourceFiles);
249 if (task.call()) {
250 return fileManager.getByteCode();
251 } else {
252 for (Diagnostic<? extends JavaFileObject> d : ds.getDiagnostics()) {
253 System.out.format("Line: %d, %s in %s", d.getLineNumber(), d.getMessage(null), d.getSource().getName());
254 }
255 throw new InternalError("compilation failure");
256 }
257 } catch (IOException e) {
258 throw new InternalError(e);
259 }
260 }
261
262 List<SourceFile> sources10k;
263
264 List<SourceFile> generate(int count) {
265 ArrayList<SourceFile> sources = new ArrayList<>(count);
266 for (int i = 0; i < count; i++) {
267 sources.add(new SourceFile("HelloWorld" + i,
268 "public class HelloWorld" + i + " {" +
269 " public static void main(String[] args) {" +
270 " System.out.println(\"Hellow World!\");" +
271 " }" +
272 "}"));
273 }
274 return sources;
275 }
276 //@Setup
277 public void setup() {
278 sources10k = generate(10_000);
279 }
280
281 public static void main(String args[]) throws Throwable {
282 JavacBench bench = new JavacBench();
283 bench.setup();
284
285 if (args.length >= 0) {
286 int count = Integer.parseInt(args[0]);
287 if (count > 0) {
288 bench.compile(count);
289 }
290 }
291 }
292 }
293 EOF
294 (set -x
295 rm -rf tmpclasses
296 mkdir -p tmpclasses
297 ${PRODUCT_BLD}/images/jdk/bin/javac -d tmpclasses JavacBench.java || exit 1
298 ${PRODUCT_BLD}/images/jdk/bin/jar cf JavacBench.jar -C tmpclasses . || exit 1
299 rm -rf tmpclasses
300 ) || exit 1
301 fi
302
303 #----------------------------------------------------------------------
304 CMD="$JVM_AND_ARGS \
305 -cp JavacBench.jar -XX:DumpLoadedClassList=javac.classlist \
306 -Xlog:class+load=debug:file=javac.class+load.log \
307 JavacBench 1000"
308 test-info "(STEP 1 of 5) Dump javac.classlist" &&
309 if $CMD; then
310 ls -l javac.classlist
311 wc -l javac.classlist
312 record_success
313 # remove old log
314 rm -f javac.class+load.log.*
315 else
316 record_failure
317 fi
318
319 JSA=javac-static${JSA_SUFFIX}.jsa
320
321 #----------------------------------------------------------------------
322 CMD="$JVM_AND_ARGS \
323 -Xshare:dump -XX:SharedArchiveFile=$JSA \
324 -XX:SharedClassListFile=javac.classlist \
325 -XX:+AOTClassLinking \
326 -cp JavacBench.jar \
327 -Xlog:cds=debug,cds+class=debug,cds+resolve=debug:file=javac.staticdump.log::filesize=0"
328 test-info "(STEP 2 of 5) Create Static $JSA" &&
329 if $CMD; then
330 ls -l $JSA
331 record_success
332 rm -f javac.staticdump.log.*
333 else
334 record_failure
335 fi
336
337 #----------------------------------------------------------------------
338 CMD="$JVM_AND_ARGS $EXTRA_ARGS \
339 -XX:SharedArchiveFile=$JSA \
340 -cp JavacBench.jar JavacBench $LOOPS"
341 test-info "Run with $JSA" &&
342 if $CMD; then
343 record_success
344 else
345 record_failure
346 fi
347
348 #----------------------------------------------------------------------
349 CMD="$JVM_AND_ARGS $EXTRA_ARGS \
350 -cp JavacBench.jar JavacBench $LOOPS"
351 test-info "Run with default archive" &&
352 if $CMD; then
353 record_success
354 else
355 record_failure
356 fi
357
358 #----------------------------------------------------------------------
359 CMD="$JVM_AND_ARGS $EXTRA_ARGS -Xshare:off -Xlog:cds=debug \
360 -cp JavacBench.jar JavacBench $LOOPS"
361 test-info "Run without CDS" &&
362 if $CMD; then
363 record_success
364 else
365 record_failure
366 fi
367
368 TESTS="1 2"
369
370 for i in $TESTS; do
371 if test $i = 2; then
372 REPLAY=" (With Training Data Replay)"
373 X1="-XX:+UnlockDiagnosticVMOptions -XX:+AOTRecordTraining"
374 X2="-XX:+UnlockDiagnosticVMOptions -XX:+AOTReplayTraining"
375 STEP3="(STEP 3 of 5) "
376 STEP4="(STEP 4 of 5) "
377 STEP5="(STEP 5 of 5) "
378 fi
379
380 DYNJSA=javac-dynamic1${JSA_SUFFIX}-$i.jsa
381
382 #----------------------------------------------------------------------
383 CMD="$JVM_AND_ARGS $EXTRA_ARGS -Xlog:cds=debug \
384 -cp JavacBench.jar -XX:ArchiveClassesAtExit=$DYNJSA $X1 JavacBench $LOOPS"
385 test-info "Dump CDS dynamic archive$REPLAY" &&
386 if $CMD; then
387 record_success
388 else
389 record_failure
390 fi
391
392
393 #----------------------------------------------------------------------
394 CMD="$JVM_AND_ARGS $EXTRA_ARGS -Xlog:cds \
395 -cp JavacBench.jar -XX:SharedArchiveFile=$DYNJSA $X2 JavacBench $LOOPS"
396 test-info "Use CDS dynamic archive$REPLAY" &&
397 if $CMD; then
398 record_success
399 else
400 record_failure
401 fi
402
403 JSA2=javac-dynamic2${JSA_SUFFIX}-$i.jsa
404 if test "$JSA2" = "javac-dynamic2-2.jsa"; then
405 JSA2=javac-dynamic.jsa
406 fi
407
408 #----------------------------------------------------------------------
409 CMD="$JVM_AND_ARGS $EXTRA_ARGS -Xlog:cds=debug,cds+class=debug:file=javac.dynamicdump.log::filesize=0 \
410 -XX:SharedArchiveFile=$JSA -XX:ArchiveClassesAtExit=$JSA2 $X1 \
411 -cp JavacBench.jar JavacBench $LOOPS"
412 test-info "${STEP3}Run with $JSA and dump profile in $JSA2${REPLAY}" &&
413 if $CMD; then
414 record_success
415 else
416 record_failure
417 fi
418
419 #----------------------------------------------------------------------
420 CMD="$JVM_AND_ARGS $EXTRA_ARGS \
421 -XX:SharedArchiveFile=$JSA2 $X2 \
422 -cp JavacBench.jar JavacBench $LOOPS"
423 test-info "Run with $JSA2 $REPLAY" &&
424 if $CMD; then
425 record_success
426 else
427 record_failure
428 fi
429
430 #----------------------------------------------------------------------
431 CMD="$JVM_AND_ARGS $EXTRA_ARGS -Xlog:aot+codecache*=warning:file=javac.aot-store.log::filesize=0 \
432 -XX:SharedArchiveFile=$JSA2 $X2 -XX:+StoreCachedCode -XX:CachedCodeFile=${JSA2}-sc -XX:CachedCodeMaxSize=100M \
433 -cp JavacBench.jar JavacBench $LOOPS"
434 test-info "${STEP4}Run with $JSA2 and generate AOT code" &&
435 if $CMD; then
436 record_success
437 else
438 record_failure
439 fi
440
441 #----------------------------------------------------------------------
442 CMD="$JVM_AND_ARGS $EXTRA_ARGS -Xlog:aot+codecache*=warning:file=javac.aot-load.log::filesize=0 \
443 -XX:SharedArchiveFile=$JSA2 $X2 -XX:+LoadCachedCode -XX:CachedCodeFile=${JSA2}-sc \
444 -cp JavacBench.jar JavacBench $LOOPS"
445 test-info "${STEP5}Final production run: with $JSA2 and load AOT code" &&
446 if $CMD; then
447 record_success
448 else
449 record_failure
450 fi
451 done
452
453 echo ===SUMMARY===
454 for (( i=1; i<=$TEST_NUM; i++ )) ; do
455 if test "${status[$i]}" != ""; then
456 echo ......................
457 echo $i ${infos[$i]} = ${status[$i]}
458 echo " $(echo ${cmds[$i]})"
459 fi
460 done
461
462 if test "$somefailed" = "1"; then
463 echo ""
464 echo '***********************SOME TESTS FAILED ********************************************'
465 echo ""
466 for (( i=1; i<=$TEST_NUM; i++ )) ; do
467 if test "${status[$i]}" = "FAILED"; then
468 echo $i ${infos[$i]} = ${status[$i]}
469 fi
470 done
471 echo ""
472 elif test "$somepassed" = "1"; then
473 echo ""
474 echo '*** all passed *****'
475 echo ""
476 fi