1 # Copyright (c) 2023, 2024, 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 # Overview 24 # 25 # This file provides the framework for running start-up benchmarks that have very 26 # short elapsed time. 27 # 28 # The goal is to be able measure very minor improvements (under 1%) even when there 29 # are system noises. 30 # 31 # - Measure the entire elapsed time with 'perf stat -r 16 bin/java .....' 32 # - Interleave the execution of the test JVMs. This way, the effect of system noises 33 # (CPU overheating, throttling, background tasks) is likely evenly distributed across 34 # the test JVMs. 35 # - Save the results in a CSV file so you can load it in a spreadsheet and manually 36 # check for noisy samples. 37 # 38 # NOTE: you can see the effect of CPU throttling in the sample data below. See the 39 # 2_xon column, which goes from 123ms when the CPU is cold to 128ms when the CPU is hot. 40 41 #====================================================================== 42 # Config 43 # 44 # See ../javac_helloworld/run.sh for an example of using this file 45 # 46 # Before sourcing this file 47 # The caller script should set up the following variables 48 49 # required 50 # CMDLINE 51 # APP 52 # optional 53 # HEAP_SIZE 54 # RUNS 55 # REPEAT 56 57 # The number of the outer loop 58 if test "$RUNS" = ""; then 59 RUNS=10 60 fi 61 62 # The number passed to "perf stat -r" 63 if test "$REPEAT" = ""; then 64 REPEAT=16 65 fi 66 67 #====================================================================== 68 # Example 69 # 70 # FYI: Results I got on 2023/12/21, Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz, 32MB RAM 71 # With JDK mainline repo and leyden-premain branch that are pretty up to date. 72 # 73 # $ cd test/hotspot/jtreg/premain/javac_helloworld 74 # $ bash run.sh /bld/mainline/images/jdk/bin/java /bld/leyden/images/jdk/bin/java 75 # 76 # ===report.csv================================================ 77 # Run,1_xoff,1_xon,2_xon,2_td,2_aot 78 # 1,313.86000,164.25000,123.031000,96.849000,92.38000 79 # 2,324.59000,163.745000,122.550000,97.730000,92.45000 80 # 3,313.61000,164.222000,122.91000,100.59000,91.18000 81 # 4,316.58000,163.779000,124.673000,101.085000,95.10000 82 # 5,313.002000,162.854000,126.240000,102.423000,91.81000 83 # 6,314.97000,166.020000,126.148000,101.159000,91.43000 84 # 7,313.30000,168.23000,128.19000,101.956000,88.13000 85 # 8,314.67000,169.04000,126.168000,102.220000,91.90000 86 # 9,313.26000,167.864000,125.856000,102.57000,90.75000 87 # 10,318.14000,169.075000,128.055000,103.523000,93.61000 88 # ==============================jvm1 /bld/mainline/images/jdk/bin/java 89 # [1_xoff] Mainline JDK (CDS disabled) 315.58 ms 90 # [1_xon ] Mainline JDK (CDS enabled) 165.89 ms 91 # ==============================jvm2 /bld/leyden/images/jdk/bin/java 92 # [2_xon ] Premain Prototype (CDS ) 125.37 ms 93 # [2_td ] Premain Prototype (CDS + Training Data) 100.99 ms 94 # [2_aot ] Premain Prototype (CDS + Training Data + AOT) 91.86 ms 95 # 96 #====================================================================== 97 98 99 # "$@" is the command-line specified by the user. Each element specifies a 100 # JVM (which optionally can contain VM parameters). 101 # 102 # We automatically detect whether the JVM is from the mainline, or from the leyden 103 # repo. 104 function main () { 105 do_dump "$@" 106 do_exec "$@" 107 do_summary "$@" 108 } 109 110 function do_dump () { 111 if test "$NODUMP" != ""; then 112 return 113 fi 114 115 local n=0 116 for i in "$@"; do 117 n=$(expr $n + 1) 118 JAVA="$i" 119 if test "$HEAP_SIZE" != ""; then 120 JAVA="$JAVA $HEAP_SIZE" 121 fi 122 dump_one_jvm $n 123 done 124 } 125 126 function do_exec () { 127 if test "$NOEXEC" != ""; then 128 return 129 fi 130 131 rm -rf logs 132 mkdir -p logs 133 rm -f report.csv 134 135 REPORT_HEADER='Run' 136 137 local n=0 138 for i in "$@"; do 139 n=$(expr $n + 1) 140 JAVA="$i" 141 if test "$HEAP_SIZE" != ""; then 142 JAVA="$JAVA $HEAP_SIZE" 143 fi 144 local APPID=$APP-jvm$n 145 if test -f $APPID-mainline.classlist; then 146 REPORT_HEADER=${REPORT_HEADER},${n}_xoff 147 REPORT_HEADER=${REPORT_HEADER},${n}_xon 148 else 149 REPORT_HEADER=${REPORT_HEADER},${n}_xon 150 REPORT_HEADER=${REPORT_HEADER},${n}_td 151 REPORT_HEADER=${REPORT_HEADER},${n}_aot 152 fi 153 #report jvm$n = $JAVA 154 done 155 156 report $REPORT_HEADER 157 158 # The #0 run is to warm up the CPU and is not counted 159 for r in $(seq 0 $RUNS); do 160 if test $r = 0; then 161 echo "RUN $r (warmup - discarded)" 162 else 163 echo "RUN $r of $RUNS" 164 fi 165 RUNLOG=$r 166 local n=0 167 for i in "$@"; do 168 n=$(expr $n + 1) 169 JAVA="$i" 170 if test "$HEAP_SIZE" != ""; then 171 JAVA="$JAVA $HEAP_SIZE" 172 fi 173 echo === jvm$n 174 exec_one_jvm $n $r 175 done 176 177 if test $r -gt 0; then 178 report $RUNLOG 179 else 180 echo $RUNLOG 181 fi 182 done 183 } 184 185 function dump_one_jvm () { 186 local binjava=$(echo $JAVA | sed -e 's/ .*//g') 187 local APPID=$APP-jvm$1 188 189 if $JAVA --version > /dev/null; then 190 if $JAVA -XX:+PrintFlagsFinal --version | grep CDSManualFinalImage > /dev/null; then 191 local is_premain=1 192 local type_msg="(premain 5 step)" 193 else 194 local is_premain=0 195 local type_msg="(mainline )" 196 fi 197 else 198 echo "$JAVA doesn't seem to be a real JVM" 199 exit 1 200 fi 201 202 echo ======================================== 203 echo dumping archive "$type_msg" for $JAVA 204 echo ======================================== 205 206 if test $is_premain = 0; then 207 echo "(Mainline) Dump classlist" 208 (set -x; $JAVA -Xshare:off -XX:DumpLoadedClassList=$APPID-mainline.classlist $CMDLINE) || exit 1 209 210 echo "(Mainline) Dump CDS archive" 211 rm -f $APPID-mainline-static.dump.log 212 (set -x; $JAVA -Xshare:dump -XX:SharedArchiveFile=$APPID-mainline.jsa -XX:SharedClassListFile=$APPID-mainline.classlist \ 213 -Xlog:cds=debug,cds+class=debug:file=$APPID-mainline-static.dump.log::filesize=0 $CMDLINE) || exit 1 214 215 else 216 # FIXME -- add support for new workflow 217 LEYDEN_OPTS="-XX:+AOTClassLinking" 218 219 echo "(Premain STEP 1 of 5) Dump classlist" 220 (set -x; $JAVA -Xshare:off -XX:DumpLoadedClassList=$APPID.classlist $CMDLINE) || exit 1 221 222 echo "(Premain STEP 2 of 5) Create Static $APPID-static.jsa" 223 rm -f $APPID-static.dump.log 224 (set -x; $JAVA -Xshare:dump $LEYDEN_OPTS -XX:SharedArchiveFile=$APPID-static.jsa -XX:SharedClassListFile=$APPID.classlist \ 225 -Xlog:cds=debug,cds+class=debug,cds+resolve=debug:file=$APPID-static.dump.log::filesize=0 $CMDLINE) || exit 1 226 227 228 echo "(Premain STEP 3 of 5) Run with $APPID-static.jsa and dump profile in $APPID-dynamic.jsa (With Training Data Replay)" 229 rm -f $APPID-dynamic.dump.log 230 (set -x; $JAVA -XX:SharedArchiveFile=$APPID-static.jsa -XX:ArchiveClassesAtExit=$APPID-dynamic.jsa -XX:+RecordTraining \ 231 -Xlog:cds=debug,cds+class=debug:file=$APPID-dynamic.dump.log::filesize=0 $CMDLINE) || exit 1 232 233 echo "(Premain 4 of 5) Run with $APPID-dynamic.jsa and generate AOT code" 234 rm -f $APPID-store-sc.log 235 (set -x; $JAVA -XX:SharedArchiveFile=$APPID-dynamic.jsa -XX:+ReplayTraining -XX:+StoreCachedCode \ 236 -Xlog:scc*=warning:file=$APPID-store-sc.log::filesize=0 \ 237 -XX:CachedCodeFile=$APPID-dynamic.jsa-sc -XX:CachedCodeMaxSize=100M $CMDLINE) || exit 1 238 239 fi 240 } 241 242 function exec_one_jvm () { 243 local APPID=$APP-jvm$1 244 245 if test -f $APPID-mainline.classlist; then 246 (set -x; 247 perf stat -r $REPEAT $JAVA -Xshare:off $CMDLINE 2> logs/${1}_xoff.$2 248 ) 249 RUNLOG=$RUNLOG,$(get_elapsed logs/${1}_xoff.$2) 250 251 (set -x; 252 perf stat -r $REPEAT $JAVA -XX:SharedArchiveFile=$APPID-mainline.jsa $CMDLINE 2> logs/${1}_xon.$2 253 ) 254 RUNLOG=$RUNLOG,$(get_elapsed logs/${1}_xon.$2) 255 fi 256 257 if test -f $APPID.classlist; then 258 (set -x; 259 perf stat -r $REPEAT $JAVA -XX:SharedArchiveFile=$APPID-static.jsa $CMDLINE 2> logs/${1}_xon.$2 260 ) 261 RUNLOG=$RUNLOG,$(get_elapsed logs/${1}_xon.$2) 262 (set -x; 263 perf stat -r $REPEAT $JAVA -XX:SharedArchiveFile=$APPID-dynamic.jsa -XX:+ReplayTraining \ 264 $CMDLINE 2> logs/${1}_td.$2 265 ) 266 RUNLOG=$RUNLOG,$(get_elapsed logs/${1}_td.$2) 267 (set -x; 268 perf stat -r $REPEAT $JAVA -XX:SharedArchiveFile=$APPID-dynamic.jsa -XX:+ReplayTraining -XX:+LoadCachedCode \ 269 -XX:CachedCodeFile=$APPID-dynamic.jsa-sc -Xlog:scc=error \ 270 $CMDLINE 2> logs/${1}_aot.$2 271 ) 272 RUNLOG=$RUNLOG,$(get_elapsed logs/${1}_aot.$2) 273 fi 274 } 275 276 function get_elapsed () { 277 elapsed=$(bc <<< "scale=3; $(cat $1 | grep elapsed | sed -e 's/[+].*//') * 1000") 278 echo $elapsed >> $1.elapsed 279 echo $elapsed 280 } 281 282 283 function report () { 284 echo "$@" 285 echo "$@" >> report.csv 286 } 287 288 function geomean () { 289 printf "%6.2f ms" $(awk 'BEGIN{E = exp(1);} $1>0{tot+=log($1); c++} END{m=tot/c; printf "%.2f\n", E^m}' $*) 290 } 291 292 293 294 function do_summary () { 295 echo ===report.csv================================================ 296 cat report.csv 297 298 mkdir -p logs/warmup 299 mv logs/*.0.elapsed logs/*.0 logs/warmup 300 local n=0 301 for i in "$@"; do 302 n=$(expr $n + 1) 303 local APPID=$APP-jvm$n 304 report ==============================jvm$n $i 305 if test -f $APPID-mainline.classlist; then 306 report "[$(printf %-6s ${n}_xoff)] Mainline JDK (CDS disabled) $(geomean logs/${n}_xoff.*.elapsed)" 307 report "[$(printf %-6s ${n}_xon )] Mainline JDK (CDS enabled) $(geomean logs/${n}_xon.*.elapsed)" 308 else 309 report "[$(printf %-6s ${n}_xon )] Premain Prototype (CDS ) $(geomean logs/${n}_xon.*.elapsed)" 310 report "[$(printf %-6s ${n}_td )] Premain Prototype (CDS + Training Data) $(geomean logs/${n}_td.*.elapsed)" 311 report "[$(printf %-6s ${n}_aot )] Premain Prototype (CDS + Training Data + AOT) $(geomean logs/${n}_aot.*.elapsed)" 312 fi 313 done 314 } 315 316 main "$@"