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:scc -Xlog:scc,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:+RecordTraining"
374         X2="-XX:+ReplayTraining"
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:scc*=warning:file=javac.scc-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:scc*=warning:file=javac.scc-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