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 # Leyden-premain + spring-petclinic demo (https://github.com/spring-projects/spring-petclinic)
 24 #
 25 # Build spring-petclinic:
 26 #    make app
 27 #
 28 # Build all leyden optimization artifacts (this is using the older "4 step training run" which will be simplified):
 29 #    make aot
 30 #
 31 # Run with Leyden optimizations
 32 #    make run
 33 #
 34 # Run without Leyden optimizations
 35 #    make run0
 36 
 37 # Set the following to point to youd "Build JDK", your JDK mainline build, and your Leyden JDK build.
 38 #
 39 #  *** NOTE: JDK 21 (or 17) is needed to build spring-petclinic-3.2.0-SNAPSHOT.jar
 40 BLDJDK_HOME   = /jdk3/official/jdk21
 41 
 42 # Points to your build with https://github.com/openjdk/jdk
 43 # For comparison purposes, this build should be the latest version of the mainline that
 44 # has been merged into https://github.com/openjdk/leyden/tree/premain
 45 MAINLINE_HOME = /jdk3/bld/rum/images/jdk
 46 
 47 # Points to your build with https://github.com/openjdk/leyden/tree/premain
 48 PREMAIN_HOME = /jdk3/bld/le4/images/jdk
 49 #===============================================================================
 50 
 51 LOG_INIT = -Xlog:init
 52 
 53 # Options passed to PREMAIN_JAVA. See compare_premain_builds below
 54 PM_OPTS =
 55 
 56 # Usually there's no need to change the following
 57 JAR_CMD          = ${BLDJDK_HOME}/bin/jar
 58 JAVAC_CMD        = ${BLDJDK_HOME}/bin/javac
 59 BLDJDK_JAVA       = ${BLDJDK_HOME}/bin/java
 60 MAINLINE_JAVA    = ${MAINLINE_HOME}/bin/java
 61 PREMAIN_JAVA     = ${PREMAIN_HOME}/bin/java ${PM_OPTS}
 62 PC_REPO          = petclinic-snapshot
 63 PC_JAVA_SOURCES = ${PC_REPO}/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java
 64 PC_APP_JAR       = ${PC_REPO}/target/spring-petclinic-3.2.0-SNAPSHOT.jar
 65 PC_APP_UNPACKED  = ${PC_REPO}/target/unpacked
 66 
 67 # This is for uploading to artifactory, to be tested with
 68 # ../../runtime/cds/appcds/leyden/SpringPetClinic.java
 69 PC_APP_UNPACKED_ZIP = ${PC_REPO}/target/spring-petclinic-3.2.0.zip
 70 
 71 PC_MAIN_CLASS    = org.springframework.samples.petclinic.PetClinicApplication
 72 
 73 # Note: you can add specify PM_VER (PreMain Version) for comparing the performance of different builds of premain.
 74 # See the compare_premain_builds target below
 75 
 76 # old workflow
 77 PC_CLASSLIST     = spring-petclinic$(PM_VER).classlist
 78 PC_STATIC_JSA    = spring-petclinic$(PM_VER).static.jsa
 79 PC_DYNAMIC_JSA   = spring-petclinic$(PM_VER).dynamic.jsa
 80 PC_CACHED_CODE   = spring-petclinic$(PM_VER).code.jsa
 81 
 82 PC_STATIC_JSA_8315737  = spring-petclinic$(PM_VER).8315737.static.jsa
 83 
 84 # new workflow
 85 PC_CDS_PREIMAGE  = spring-petclinic$(PM_VER).cds.preimage
 86 PC_CDS           = spring-petclinic$(PM_VER).cds
 87 
 88 # TODO: should we add -Dspring.context.exit=onRefresh to command line??
 89 # This will make the JVM quit after printing this line:
 90 #
 91 #    4:21.639 ... o.s.b.a.e.web.EndpointLinksResolver      : Exposing 13 endpoint(s) beneath base path '/actuator'
 92 #
 93 # Whereas -DautoQuit=true will make it exit after printing the following (a little bit of application code is executed)
 94 #
 95 #    4:21.665 ... o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path ''
 96 #    4:21.666 ... o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 1.358 seconds (process running for 1.584)
 97 #    #### Booted and returned in 1453ms
 98 #    4:21.692 ... j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
 99 #    4:21.693 ... com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
100 #    4:21.694 ... com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
101 HEAP_SIZE        = -Xmx2g
102 UNPACKED_CMDLINE = $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath -DautoQuit=true -Dspring.aot.enabled=true -Dspring.output.ansi.enabled=NEVER ${PC_MAIN_CLASS}
103 DUMMY_CMDLINE    = $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath.dummy Dummy
104 
105 all: check git app aot
106 
107 check:
108 	@if ${PREMAIN_JAVA} -XX:+PrintFlagsFinal --version | grep -q CDSManualFinalImage; then \
109 	    true; \
110 	else \
111 	    echo PREMAIN_HOME should point to your build of https://github.com/openjdk/leyden/tree/premain; \
112 	    exit 1; \
113 	fi
114 
115 # A bunch of quick targets so you can type "make list" to create the classlist, etc
116 git: ${PC_JAVA_SOURCES}
117 app: ${PC_APP_JAR}
118 unpack: ${PC_APP_UNPACKED}
119 
120 # The "4 step training run" workflow -- this will soon be replaced with the new workflow in ../javac_new_workflow/
121 list: ${PC_CLASSLIST}
122 static: ${PC_STATIC_JSA}
123 dynamic: ${PC_DYNAMIC_JSA}
124 aot: ${PC_CACHED_CODE}
125 
126 # Check out this specific version of spring-petclinic that we have been testing with.
127 # https://github.com/spring-projects/spring-petclinic/commit/80fd11067c4662486e4c635deceba927375b621c
128 #    Author: Dave Syer <dsyer@vmware.com>
129 #    Date:   Wed Jan 10 05:01:00 2024
130 #        Upgrade to Boot 3.2.1
131 ${PC_JAVA_SOURCES}:
132 	rm -rf ${PC_REPO}
133 	git clone https://github.com/spring-projects/spring-petclinic ${PC_REPO}
134 	cd ${PC_REPO}; git reset --hard 80fd11067c4662486e4c635deceba927375b621c
135 	cd ${PC_REPO}; git apply ../premain-patch.diff
136 
137 # Need to touch ${PC_APP_JAR} as mvn wants to set it the release date of 3.2.0-SNAPSHOT
138 ${PC_APP_JAR}: ${PC_JAVA_SOURCES}
139 	cd ${PC_REPO}; JAVA_HOME=${BLDJDK_HOME} mvn -Dmaven.test.skip=true package
140 	if test -f ${PC_APP_JAR}; then \
141 	    touch ${PC_APP_JAR}; \
142 	fi
143 
144 ${PC_APP_UNPACKED}: ${PC_APP_JAR}
145 	rm -rf ${PC_APP_UNPACKED}
146 	mkdir -p ${PC_APP_UNPACKED}
147 	cd ${PC_APP_UNPACKED} && \
148 	    ${JAR_CMD} xf ../spring-petclinic-3.2.0-SNAPSHOT.jar && \
149 	    ${JAR_CMD} cf classes.jar META-INF org && \
150             cd BOOT-INF/classes/ && \
151 	    ${JAR_CMD} cf classes.jar *
152 	echo ${PC_APP_UNPACKED}/classes.jar $$(find ${PC_APP_UNPACKED}/BOOT-INF -name \*.jar | sort) \
153 	    | sed -e 's/ /:/g' > ${PC_APP_UNPACKED}/classpath
154 	echo $$(cat ${PC_APP_UNPACKED}/classpath):Dummy.jar > ${PC_APP_UNPACKED}/classpath.dummy
155 	${JAR_CMD} cf0 ${PC_APP_UNPACKED_ZIP} ${PC_APP_UNPACKED}
156 	$(MAKE) runb
157 
158 #uncomment this to see the generated classes for dynamic proxies
159 #SAVE_GEN_FILES=-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true
160 
161 ${PC_CLASSLIST}: ${PC_APP_UNPACKED}
162 	${PREMAIN_JAVA} -Xshare:off -XX:DumpLoadedClassList=${PC_CLASSLIST} \
163 	    -Xlog:class+load=debug:file=${PC_CLASSLIST}.classload.log ${SAVE_GEN_FILES} \
164 	    ${UNPACKED_CMDLINE}
165 	wc -lc ${PC_CLASSLIST}
166 
167 ${PC_STATIC_JSA}: ${PC_CLASSLIST}
168 	rm -f ${PC_STATIC_JSA}.log
169 	${PREMAIN_JAVA} -Xshare:dump -XX:SharedClassListFile=${PC_CLASSLIST} $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath \
170 	    -XX:SharedArchiveFile=${PC_STATIC_JSA} \
171 	    -XX:+AOTClassLinking -XX:+ArchiveDynamicProxies -XX:+ArchiveReflectionData \
172 	    -XX:+ArchiveLoaderLookupCache -Dcds.debug.archived.packages=1 \
173 	    -Xlog:cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=${PC_STATIC_JSA}.log
174 	ls -l ${PC_STATIC_JSA}
175 
176 ${PC_STATIC_JSA_8315737}: ${PC_CLASSLIST}
177 	rm -f ${PC_STATIC_JSA}.log
178 	${PREMAIN_JAVA} -Xshare:dump -XX:SharedClassListFile=${PC_CLASSLIST} $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath \
179 	    -XX:SharedArchiveFile=${PC_STATIC_JSA_8315737} \
180 	    -XX:+AOTClassLinking -XX:-ArchiveDynamicProxies -XX:-ArchiveReflectionData \
181 	    -XX:-ArchiveLoaderLookupCache -XX:-ArchiveProtectionDomains -XX:-ArchivePackages \
182 	    -Xlog:cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=${PC_STATIC_JSA_8315737}.log
183 	ls -l ${PC_STATIC_JSA_8315737}
184 
185 ${PC_DYNAMIC_JSA}: ${PC_STATIC_JSA}
186 	rm -f ${PC_DYNAMIC_JSA} ${PC_DYNAMIC_JSA}.log
187 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} -XX:ArchiveClassesAtExit=${PC_DYNAMIC_JSA} \
188 	    -Xlog:cds=debug,cds+class=debug,cds+resolve=debug:file=${PC_DYNAMIC_JSA}.log \
189 	    -XX:+RecordTraining ${UNPACKED_CMDLINE}
190 	ls -l ${PC_DYNAMIC_JSA}
191 
192 ${PC_CACHED_CODE}: ${PC_DYNAMIC_JSA}
193 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_JSA} -XX:+ReplayTraining -XX:+StoreCachedCode \
194 	     -XX:CachedCodeFile=${PC_CACHED_CODE} -XX:CachedCodeMaxSize=512M ${UNPACKED_CMDLINE}
195 	ls -l ${PC_CACHED_CODE}
196 
197 # run with premain optimizatipn
198 run: ${PC_CACHED_CODE}
199 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_JSA} -XX:+ReplayTraining -XX:+LoadCachedCode \
200 		-XX:CachedCodeFile=${PC_CACHED_CODE} ${LOG_INIT} -Xlog:scc=error ${UNPACKED_CMDLINE}
201 
202 # run with just static CDS archive
203 runs: ${PC_STATIC_JSA}
204 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} ${LOG_INIT} ${UNPACKED_CMDLINE}
205 
206 # run with just static CDS archive
207 runs.8315737: ${PC_STATIC_JSA_8315737}
208 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA_8315737} ${LOG_INIT} ${UNPACKED_CMDLINE}
209 
210 runs.jep: runs.8315737
211 
212 # run with just static CDS archive, but instead of the main class, give a fake class name
213 # Because -XX:+LoadSharedClasses is specified, this command will basically test the speed of loading all
214 # the classes and entering the main() method.
215 dummy: ${PC_STATIC_JSA} Dummy.jar
216 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} ${LOG_INIT} ${DUMMY_CMDLINE}
217 
218 dummy-50: ${PC_STATIC_JSA} Dummy.jar
219 	bash -c "time for i in {1..50}; do ${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} ${DUMMY_CMDLINE}; done"
220 
221 dummy-50-perf: ${PC_STATIC_JSA} Dummy.jar
222 	perf stat -r 50 ${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} ${DUMMY_CMDLINE}
223 
224 Dummy.jar: Dummy.java
225 	${JAVAC_CMD} Dummy.java
226 	${JAR_CMD} cf Dummy.jar Dummy*.class
227 
228 # run with just dynamic CDS archive
229 rund: ${PC_DYNAMIC_JSA}
230 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_JSA} \
231 		${LOG_INIT} ${UNPACKED_CMDLINE}
232 
233 # run WITHOUT premain optimizatipn
234 run0: ${PC_APP_UNPACKED}
235 	${PREMAIN_JAVA} ${LOG_INIT} ${UNPACKED_CMDLINE}
236 
237 # Run using "build JDK"
238 runb: ${PC_APP_UNPACKED}
239 	${BLDJDK_JAVA} ${UNPACKED_CMDLINE}
240 
241 # Running with mainline
242 PC_CLASSLIST_MAINLINE   = spring-petclinic.ml.classlist
243 PC_STATIC_JSA_MAINLINE  = spring-petclinic.static.ml.jsa
244 
245 list.ml:   ${PC_CLASSLIST_MAINLINE}
246 
247 static.ml: ${PC_STATIC_JSA_MAINLINE}
248 
249 ${PC_CLASSLIST_MAINLINE}: ${PC_APP_UNPACKED}
250 	${MAINLINE_JAVA} -Xshare:off -XX:DumpLoadedClassList=${PC_CLASSLIST_MAINLINE} \
251 	    -Xlog:class+load=debug:file=spring-petclinic.classload.ml.log \
252 	    ${UNPACKED_CMDLINE}
253 	wc -lc ${PC_CLASSLIST_MAINLINE}
254 
255 ${PC_STATIC_JSA_MAINLINE}: ${PC_CLASSLIST_MAINLINE}
256 	rm -f ${PC_STATIC_JSA_MAINLINE}.log
257 	${MAINLINE_JAVA} -Xshare:dump -XX:SharedClassListFile=${PC_CLASSLIST_MAINLINE} $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath \
258 	    -XX:SharedArchiveFile=${PC_STATIC_JSA_MAINLINE} \
259 	    -Xlog:cds=debug,cds+class=debug,cds+heap=warning:file=${PC_STATIC_JSA_MAINLINE}.log
260 	ls -l ${PC_STATIC_JSA_MAINLINE}
261 
262 run0.ml: ${PC_STATIC_JSA_MAINLINE}
263 	${MAINLINE_JAVA} \
264 		${UNPACKED_CMDLINE}
265 
266 runs.ml: ${PC_STATIC_JSA_MAINLINE}
267 	${MAINLINE_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA_MAINLINE} \
268 		${UNPACKED_CMDLINE}
269 
270 clean.ml:
271 	rm -fv ${PC_CLASSLIST_MAINLINE}* ${PC_STATIC_JSA_MAINLINE}*
272 
273 #======================================== new workflow
274 pre: ${PC_CDS_PREIMAGE}
275 cds: ${PC_CDS}
276 
277 ${PC_CDS_PREIMAGE}: ${PC_APP_UNPACKED}
278 	rm -f ${PC_CDS_PREIMAGE} ${PC_CDS}
279 	${PREMAIN_JAVA} -XX:+AOTClassLinking \
280 	    -XX:+ArchiveReflectionData \
281 	    -XX:+ArchiveDynamicProxies -XX:+ArchiveLoaderLookupCache -XX:CachedCodeMaxSize=512M \
282 	    -XX:+UnlockDiagnosticVMOptions -XX:+CDSManualFinalImage -XX:CacheDataStore=${PC_CDS} \
283 	    -Xlog:cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=${PC_CDS_PREIMAGE}.log \
284 	    ${UNPACKED_CMDLINE}
285 	ls -l ${PC_CDS_PREIMAGE}
286 
287 ${PC_CDS}: ${PC_CDS_PREIMAGE}
288 	rm -f ${PC_CDS}
289 	${PREMAIN_JAVA} -XX:+AOTClassLinking -XX:CachedCodeMaxSize=512M \
290 	    -XX:+UnlockDiagnosticVMOptions -XX:CDSPreimage=${PC_CDS_PREIMAGE} -XX:CacheDataStore=${PC_CDS} \
291 	    -Xlog:scc,cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=${PC_CDS}.log \
292 	    -Dcds.debug.archived.packages=1 \
293 	    ${UNPACKED_CMDLINE}
294 	ls -l ${PC_CDS}
295 	ls -l ${PC_CDS}.code
296 
297 # run with NEW workflow
298 runn: ${PC_CDS}
299 	${PREMAIN_JAVA} -XX:CacheDataStore=${PC_CDS} ${LOG_INIT} -Xlog:scc=error ${UNPACKED_CMDLINE}
300 
301 # see dummy above
302 dummyn: ${PC_CDS} Dummy.jar
303 	${PREMAIN_JAVA} -XX:CacheDataStore=${PC_CDS} ${LOG_INIT} -Xlog:scc=error ${DUMMY_CMDLINE}
304 
305 dummyn-50: ${PC_CDS} Dummy.jar
306 	bash -c "time for i in {1..50}; do ${PREMAIN_JAVA} -XX:CacheDataStore=${PC_CDS} \
307 		-XX:-ReplayTraining -XX:-LoadCachedCode -Xlog:scc=error ${DUMMY_CMDLINE}; done"
308 
309 dummyn-50-perf: ${PC_CDS} Dummy.jar
310 	perf stat -r 50 ${PREMAIN_JAVA} -XX:CacheDataStore=${PC_CDS} -XX:-ReplayTraining -XX:-LoadCachedCode -Xlog:scc=error ${DUMMY_CMDLINE}
311 
312 clean: clean0
313 	rm -rf *~ ${PC_REPO} Dummy*.class Dummy.jar *.old.txt *.new.txt tmp.txt hs_err*
314 
315 # clean the the leyden artifacts
316 clean0:
317 	rm -fv spring-petclinic.*
318 
319 # clean the the leyden artifacts for the new workflow only
320 cleann:
321 	rm -fv spring-petclinic.cds.*
322 
323 include ../lib/Bench.gmk
324 
325 # Same as mainline_vs_premain in ../lib/Bench.gmk, but also includes old workflow
326 mainline_vs_premain_all: clean0 _mainline_vs_premain_all
327 
328 _mainline_vs_premain_all:
329 	@echo "run,mainline default,mainline custom static CDS,premain custom static CDS,premain custom static CDS+training+AOT,premain new workflow"
330 	@first=1; for i in ${LOOPS}; do \
331 		rm -f tmp.txt; \
332 		$(SLEEP) $(MAKE) LOG_INIT= run0.ml | grep Booted >> tmp.txt; \
333 		$(SLEEP) $(MAKE) LOG_INIT= runs.ml | grep Booted >> tmp.txt; \
334 		$(SLEEP) $(MAKE) LOG_INIT= runs    | grep Booted >> tmp.txt; \
335 		$(SLEEP) $(MAKE) LOG_INIT= run     | grep Booted >> tmp.txt; \
336 		$(SLEEP) $(MAKE) LOG_INIT= runn    | grep Booted >> tmp.txt; \
337 		if test "$$first" != "1"; then \
338 		    echo $$i$$(cat tmp.txt | sed -e 's/.*in /,/g' -e 's/ms//g') | sed -e 's/ //g'; \
339 	        fi; \
340 		first=0; \
341 	done
342 
343 # Compare
344 # (1) Mainline JDK with default CDS archive only
345 # (2) Mainline JDK with a custom (static) CDS archive for PetClinic
346 # (3) Premain with a custom (static) CDS archive for PetClinic, with only the optimizations in https://openjdk.org/jeps/8315737
347 mainline_vs_premain_jep_8315737: clean0 _mainline_vs_premain_jep_8315737
348 
349 _mainline_vs_premain_jep_8315737:
350 	rm -f mainline_vs_premain_jep_8315737.csv
351 	@echo "run,mainline default,mainline custom static CDS,premain custom static CDS (JEP 8315737 only),premain custom static CDS (all optimizations),premain all optimizations (incl profiles and AOT)" | \
352 	    tee -a mainline_vs_premain_jep_8315737.csv
353 	@first=1; for i in ${LOOPS}; do \
354 		rm -f tmp.txt; \
355 		$(SLEEP) $(MAKE) LOG_INIT= run0.ml      | grep Booted >> tmp.txt; \
356 		$(SLEEP) $(MAKE) LOG_INIT= runs.ml      | grep Booted >> tmp.txt; \
357 		$(SLEEP) $(MAKE) LOG_INIT= runs.8315737 | grep Booted >> tmp.txt; \
358 		$(SLEEP) $(MAKE) LOG_INIT= runs         | grep Booted >> tmp.txt; \
359 		$(SLEEP) $(MAKE) LOG_INIT= runn         | grep Booted >> tmp.txt; \
360 		if test "$$first" != "1"; then \
361 		    echo $$i$$(cat tmp.txt | sed -e 's/.*in /,/g' -e 's/ms//g') | sed -e 's/ //g' | tee -a mainline_vs_premain_jep_8315737.csv; \
362 	        fi; \
363 		first=0; \
364 	done
365 	@${MAINLINE_JAVA} ../lib/GithubMDChart.java mainline_vs_premain_jep_8315737.md < mainline_vs_premain_jep_8315737.csv
366 
367 # Same as compare_premain_builds in ../lib/Bench.gmk, but compare CDS only, and old workflow as well
368 
369 compare_premain_builds_full: clean0 _compare_premain_builds_full
370 
371 _compare_premain_builds_full:
372 	@echo Old build = ${PM_OLD} with options ${PM_OPTS_OLD}
373 	@echo New build = ${PM_NEW} with options ${PM_OPTS_NEW}
374 	@echo "Run,Old static CDS only,New static CDS only,Old static CDS + training + AOT,New static CDS + training + AOT,Old 1-step training,New 1-step training"
375 	@first=1; for i in ${LOOPS}; do \
376 		rm -f tmp.txt; \
377 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_OLD} PM_VER=.old PM_OPTS="${PM_OPTS_OLD}" runs | grep Booted >> tmp.txt; \
378 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_NEW} PM_VER=.new PM_OPTS="${PM_OPTS_NEW}" runs | grep Booted >> tmp.txt; \
379 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_OLD} PM_VER=.old PM_OPTS="${PM_OPTS_OLD}" run  | grep Booted >> tmp.txt; \
380 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_NEW} PM_VER=.new PM_OPTS="${PM_OPTS_NEW}" run  | grep Booted >> tmp.txt; \
381 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_OLD} PM_VER=.old PM_OPTS="${PM_OPTS_OLD}" runn | grep Booted >> tmp.txt; \
382 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_NEW} PM_VER=.new PM_OPTS="${PM_OPTS_NEW}" runn | grep Booted >> tmp.txt; \
383 		if test "$$first" != "1"; then \
384 		    echo $$i$$(cat tmp.txt | sed -e 's/.*in /,/g' -e 's/ms//g') | sed -e 's/ //g'; \
385 	        fi; \
386 		first=0; \
387 	done
388 
389 # same as above, but only compare the speed of "make runs"
390 compare_premain_builds_static: clean0 _compare_premain_builds_static
391 
392 _compare_premain_builds_static:
393 	@echo Old build = ${PM_OLD} with options ${PM_OPTS_OLD}
394 	@echo New build = ${PM_NEW} with options ${PM_OPTS_NEW}
395 	@echo "Run,Old static CDS only,New static CDS only"
396 	@first=1; for i in ${LOOPS}; do \
397 		rm -f tmp.txt; \
398 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_OLD} PM_VER=.old PM_OPTS="${PM_OPTS_OLD}" runs | grep Booted >> tmp.txt; \
399 		$(SLEEP) $(MAKE) LOG_INIT= PREMAIN_HOME=${PM_NEW} PM_VER=.new PM_OPTS="${PM_OPTS_NEW}" runs | grep Booted >> tmp.txt; \
400 		if test "$$first" != "1"; then \
401 		    echo $$i$$(cat tmp.txt | sed -e 's/.*in /,/g' -e 's/ms//g') | sed -e 's/ //g'; \
402 	        fi; \
403 		first=0; \
404 	done
405 
406 # Clean up the logs generated by compare_premain_builds, so you can see if one build includes
407 # more classes than another.
408 diff_training_logs:
409 	@for i in old new; do \
410 	    grep cds,class spring-petclinic.$$i.static.jsa.log | \
411 		sed -e 's/.*0x[0-9a-f]* ..... //g' \
412 		    -e 's/Lambda\/0x[0-9a-f]*/Lambda\/nnn/g' \
413 		    -e 's/MH\/0x[0-9a-f]*/MH\/nnn/g' | \
414 		sort > old-workflow-static-classes.$$i.txt; \
415 	    grep cds,class spring-petclinic.$$i.dynamic.jsa.log | \
416 		sed -e 's/.*0x[0-9a-f]* ..... //g' \
417 		    -e 's/Lambda\/0x[0-9a-f]*/Lambda\/nnn/g' \
418 		    -e 's/MH\/0x[0-9a-f]*/MH\/nnn/g' | \
419 		sort > old-workflow-dynamic-classes.$$i.txt; \
420 	    grep cds,class spring-petclinic.$$i.cds.log | \
421 		sed -e 's/.*0x[0-9a-f]* ..... //g' \
422 		    -e 's/Lambda\/0x[0-9a-f]*/Lambda\/nnn/g' \
423 		    -e 's/MH\/0x[0-9a-f]*/MH\/nnn/g' | \
424 		sort > new-workflow-classes.$$i.txt; \
425 	done
426 	@ls -l *.old.txt *.new.txt
427 	@echo '***'
428 	@echo "You can diff the above files to diagnose speed differences between two builds"
429 
430