1 # Copyright (c) 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 warmup (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 # Uses JMeter to drive the load to the petclinic application.
 32 # Duration of the load and number of threads used by JMeter to drive the load
 33 # is controlled by JMETER_DURATION and JMETER_THREADS variables respectively.
 34 # JMETER_CPUS and APP_CPUS variables control the cpus to be used for running the jmeter and app respectively.
 35 #
 36 # Run warmup with baseline
 37 #    make -f WarmupMakefile warmup-bl
 38 #
 39 # Run warmup with only preload optimizations
 40 #    make -f WarmupMakefile warmup-preload
 41 #
 42 # Run warmup with training data generated for the startup
 43 #    make -f WarmupMakefile warmup-st
 44 #
 45 # Run warmup with training data generated by the jmeter load
 46 #    make -f WarmupMakefile warmup-lt
 47 #
 48 # Run with startup training data and aot
 49 #    make -f WarmupMakefile warmup-st-aot
 50 #
 51 # Run with startup training data and aot
 52 #    make -f WarmupMakefile warmup-lt-aot
 53 #
 54 # Run all configurations
 55 #    make -f WarmupMakefile run
 56 #
 57 # Use warmup_result.sh to process the generated jmeter log files to create CSV files
 58 # that can be used for plotting throughput graphs
 59 #
 60 # Set the following to point to JDK 17 and your Leyden JDK build.
 61 #
 62 #  *** NOTE: JDK 17 (or 21??) is needed to build spring-petclinic-3.2.0-SNAPSHOT.jar
 63 JDK17_HOME   = /jdk3/official/jdk17
 64 #baseline java
 65 BL_HOME      = /jdk3/official/jdk-latest
 66 PREMAIN_HOME = /jdk3/bld/le4/images/jdk
 67 #===============================================================================
 68 
 69 # Usually there's no need to change the following
 70 JAR_CMD          = ${JDK17_HOME}/bin/jar
 71 JDK17_JAVA       = ${JDK17_HOME}/bin/java
 72 PREMAIN_JAVA     = ${PREMAIN_HOME}/bin/java
 73 BL_JAVA          = ${BL_HOME}/bin/java
 74 PC_REPO          = petclinic-snapshot-warmup
 75 PC_JAVA_SOURCES = ${PC_REPO}/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java
 76 PC_APP_JAR       = ${PC_REPO}/target/spring-petclinic-3.2.0-SNAPSHOT.jar
 77 PC_APP_UNPACKED  = ${PC_REPO}/target/unpacked
 78 JMETER_DIR       = apache-jmeter-5.5
 79 JMETER_BIN       = ${JMETER_DIR}/bin/jmeter
 80 JMETER_ZIP       = ${JMETER_DIR}.zip
 81 JMETER_URL       = https://archive.apache.org/dist/jmeter/binaries/${JMETER_ZIP}
 82 
 83 # This is for uploading to artifactory, to be tested with
 84 # ../../runtime/cds/appcds/leyden/SpringPetClinic.java
 85 PC_APP_UNPACKED_ZIP = ${PC_REPO}/target/spring-petclinic-3.2.0.zip
 86 
 87 PC_MAIN_CLASS    = org.springframework.samples.petclinic.PetClinicApplication
 88 PC_CLASSLIST     = spring-petclinic.classlist
 89 PC_STATIC_JSA    = spring-petclinic.static.jsa
 90 PC_DYNAMIC_ST_JSA   = spring-petclinic.dynamic-st.jsa
 91 PC_DYNAMIC_LT_JSA   = spring-petclinic.dynamic-lt.jsa
 92 PC_DYNAMIC_NOTRAINING_JSA = spring-petclinic.dynamic-notraining.jsa
 93 PC_ST_CACHED_CODE   = spring-petclinic.code-st.jsa
 94 PC_LT_CACHED_CODE   = spring-petclinic.code-lt.jsa
 95 
 96 PC_BL_CLASSLIST     = spring-petclinic.bl_classlist
 97 PC_STATIC_BL_JSA    = spring-petclinic.static_bl.jsa
 98 PC_DYNAMIC_BL_JSA   = spring-petclinic.dynamic_bl.jsa
 99 
100 PC_CDS_PREIMAGE     = spring-petclinic.cds.preimage
101 PC_CDS              = spring-petclinic.cds
102 
103 JMETER_DURATION = 180
104 JMETER_THREADS = 1
105 JMETER_CPUS = 12-13
106 APP_CPUS = 14-19
107 
108 # TODO: should we add -Dspring.context.exit=onRefresh to command line??
109 # This will make the JVM quit after printing this line:
110 #
111 #    4:21.639 ... o.s.b.a.e.web.EndpointLinksResolver      : Exposing 13 endpoint(s) beneath base path '/actuator'
112 #
113 # Whereas -DautoQuit=true will make it exit after printing the following (a little bit of application code is executed)
114 #
115 #    4:21.665 ... o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path ''
116 #    4:21.666 ... o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 1.358 seconds (process running for 1.584)
117 #    #### Booted and returned in 1453ms
118 #    4:21.692 ... j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
119 #    4:21.693 ... com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
120 #    4:21.694 ... com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
121 HEAP_SIZE        = -Xmx2g
122 UNPACKED_CMDLINE = $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath -DautoQuit=true -Dspring.aot.enabled=true -Dspring.output.ansi.enabled=NEVER ${PC_MAIN_CLASS}
123 
124 all: check git app aot
125 
126 check:
127 	@if ${JDK17_JAVA} --version | grep -q '17.*LTS'; then \
128 	    true; \
129 	else \
130 	    echo JDK17_HOME should point to JDK 17; \
131 	    exit 1; \
132 	fi
133 	@if ${PREMAIN_JAVA} -XX:+PrintFlagsFinal --version | grep -q CDSManualFinalImage; then \
134 	    true; \
135 	else \
136 	    echo PREMAIN_HOME should point to your build of https://github.com/openjdk/leyden/tree/premain; \
137 	    exit 1; \
138 	fi
139 
140 # A bunch of quick targets so you can type "make list" to create the classlist, etc
141 git: ${PC_JAVA_SOURCES}
142 app: ${PC_APP_JAR}
143 jmeter: ${JMETER_BIN}
144 unpack: ${PC_APP_UNPACKED}
145 
146 # The "4 step training run" workflow -- this will soon be replaced with the new workflow in ../javac_new_workflow/
147 list: ${PC_CLASSLIST}
148 static: ${PC_STATIC_JSA}
149 dynamic: ${PC_DYNAMIC_ST_JSA}
150 aot: ${PC_ST_CACHED_CODE}
151 
152 # Check out this specific version of spring-petclinic that we have been testing with.
153 # https://github.com/spring-projects/spring-petclinic/commit/80fd11067c4662486e4c635deceba927375b621c
154 #    Author: Dave Syer <dsyer@vmware.com>
155 #    Date:   Wed Jan 10 05:01:00 2024
156 #        Upgrade to Boot 3.2.1
157 ${PC_JAVA_SOURCES}:
158 	rm -rf ${PC_REPO}
159 	git clone https://github.com/spring-projects/spring-petclinic ${PC_REPO}
160 	cd ${PC_REPO}; git reset --hard 80fd11067c4662486e4c635deceba927375b621c
161 	cd ${PC_REPO}; git apply ../premain-patch-noautoquit.diff
162 
163 ${JMETER_BIN}:
164 	rm -fr ${JMETER_DIR}
165 	wget ${JMETER_URL}
166 	unzip -q ${JMETER_ZIP}
167 	ls -l $@
168 
169 # Need to touch ${PC_APP_JAR} as mvn wants to set it the release date of 3.2.0-SNAPSHOT
170 ${PC_APP_JAR}: ${PC_JAVA_SOURCES}
171 	cd ${PC_REPO}; JAVA_HOME=${JDK17_HOME} mvn -Dmaven.test.skip=true package
172 	if test -f ${PC_APP_JAR}; then \
173 	    touch ${PC_APP_JAR}; \
174 	fi
175 
176 ${PC_APP_UNPACKED}: ${PC_APP_JAR}
177 	rm -rf ${PC_APP_UNPACKED}
178 	mkdir -p ${PC_APP_UNPACKED}
179 	cd ${PC_APP_UNPACKED} && \
180 	    ${JAR_CMD} xf ../spring-petclinic-3.2.0-SNAPSHOT.jar && \
181 	    ${JAR_CMD} cf classes.jar META-INF org && \
182             cd BOOT-INF/classes/ && \
183 	    ${JAR_CMD} cf classes.jar *
184 	echo ${PC_APP_UNPACKED}/classes.jar $$(find ${PC_APP_UNPACKED}/BOOT-INF -name \*.jar | sort) \
185 	    | sed -e 's/ /:/g' > ${PC_APP_UNPACKED}/classpath
186 	${JAR_CMD} cf0 ${PC_APP_UNPACKED_ZIP} ${PC_APP_UNPACKED}
187 	$(MAKE) -f WarmupMakefile run17
188 
189 #uncomment this to see the generated classes for dynamic proxies
190 #SAVE_GEN_FILES=-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true
191 
192 define wait-for-startup
193 tail -n+0 -f $@.out | sed --quiet '/Booted and returned/ q'
194 endef
195 
196 define exit-app
197 cp application.pid app.pid
198 curl -X POST localhost:8080/actuator/shutdown
199 tail -f --pid=`cat app.pid` /dev/null
200 endef
201 
202 # petclinic_test_plan.jmx is derived from https://github.com/spring-projects/spring-petclinic/blob/main/src/test/jmeter/petclinic_test_plan.jmx
203 define run-jmeter
204 taskset -c "${JMETER_CPUS}" ${JMETER_BIN} -JDURATION=${JMETER_DURATION} -JTHREADS=${JMETER_THREADS} -Dsummariser.interval=6 -n -t petclinic_test_plan.jmx | tee tput-$@.log
205 endef
206 
207 ${PC_BL_CLASSLIST}: ${PC_APP_UNPACKED}
208 	${BL_JAVA} -Xshare:off -XX:DumpLoadedClassList=${PC_BL_CLASSLIST} \
209 	    -Xlog:class+load=debug:file=$@.log ${SAVE_GEN_FILES} \
210 	    ${UNPACKED_CMDLINE} &> $@.out &
211 	$(wait-for-startup)
212 	$(exit-app)
213 	wc -lc $@
214 
215 ${PC_CLASSLIST}: ${PC_APP_UNPACKED}
216 	${PREMAIN_JAVA} -Xshare:off -XX:DumpLoadedClassList=${PC_CLASSLIST} \
217 	    -Xlog:class+load=debug:file=$@.log ${SAVE_GEN_FILES} \
218 	    ${UNPACKED_CMDLINE} &> $@.out &
219 	$(wait-for-startup)
220 	$(run-jmeter)
221 	$(exit-app)
222 	wc -lc $@
223 
224 ${PC_STATIC_BL_JSA}: ${PC_BL_CLASSLIST}
225 	rm -f ${PC_STATIC_BL_JSA}.log
226 	${BL_JAVA} -Xshare:dump -XX:SharedClassListFile=${PC_BL_CLASSLIST} $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath \
227 	    -XX:SharedArchiveFile=${PC_STATIC_BL_JSA} -Xlog:cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=$@.log
228 	ls -l $@
229 
230 ${PC_STATIC_JSA}: ${PC_CLASSLIST}
231 	rm -f ${PC_STATIC_JSA}.log
232 	${PREMAIN_JAVA} -Xshare:dump -XX:SharedClassListFile=${PC_CLASSLIST} $(HEAP_SIZE) -cp @${PC_APP_UNPACKED}/classpath \
233 	    -XX:+AOTClassLinking -XX:+ArchiveDynamicProxies -XX:+ArchiveReflectionData \
234             -XX:+ArchiveLoaderLookupCache -Dcds.debug.archived.packages=1 \
235 	    -XX:SharedArchiveFile=${PC_STATIC_JSA} -Xlog:cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=$@.log
236 	ls -l $@
237 
238 ${PC_DYNAMIC_BL_JSA}: ${PC_STATIC_BL_JSA}
239 	rm -f ${PC_DYNAMIC_BL_JSA} ${PC_DYNAMIC_BL_JSA}.log
240 	${BL_JAVA} -XX:SharedArchiveFile=${PC_STATIC_BL_JSA} -XX:ArchiveClassesAtExit=${PC_DYNAMIC_BL_JSA} \
241 	    -Xlog:cds=debug,cds+class=debug,cds+resolve=debug:file=$@.log \
242 	    ${UNPACKED_CMDLINE} &> $@.out &
243 	$(wait-for-startup)
244 	$(exit-app)
245 	ls -l $@
246 
247 ${PC_DYNAMIC_NOTRAINING_JSA}: ${PC_STATIC_JSA}
248 	rm -f ${PC_DYNAMIC_NOTRAINING_JSA} ${PC_DYNAMIC_NOTRAINING_JSA}.log
249 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} -XX:ArchiveClassesAtExit=${PC_DYNAMIC_NOTRAINING_JSA} \
250 	    -Xlog:cds=debug,cds+class=debug,cds+resolve=debug:file=$@.log \
251 	    ${UNPACKED_CMDLINE} &> $@.out &
252 	$(wait-for-startup)
253 	$(exit-app)
254 	ls -l $@
255 
256 ${PC_DYNAMIC_ST_JSA}: ${PC_STATIC_JSA}
257 	rm -f ${PC_DYNAMIC_ST_JSA} ${PC_DYNAMIC_ST_JSA}.log
258 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} -XX:ArchiveClassesAtExit=${PC_DYNAMIC_ST_JSA} \
259 	    -Xlog:cds=debug,cds+class=debug,cds+resolve=debug:file=$@.log \
260 	    -XX:+RecordTraining ${UNPACKED_CMDLINE} &> $@.out &
261 	$(wait-for-startup)
262 	$(exit-app)
263 	ls -l $@
264 
265 ${PC_DYNAMIC_LT_JSA}: ${PC_STATIC_JSA}
266 	rm -f ${PC_DYNAMIC_LT_JSA} ${PC_DYNAMIC_LT_JSA}.log
267 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_STATIC_JSA} -XX:ArchiveClassesAtExit=${PC_DYNAMIC_LT_JSA} \
268 	    -Xlog:cds=debug,cds+class=debug,cds+resolve=debug:file=$@.log \
269 	    -XX:+RecordTraining ${UNPACKED_CMDLINE} &> $@.out &
270 	$(wait-for-startup)
271 	$(run-jmeter)
272 	$(exit-app)
273 	ls -l $@
274 
275 ${PC_ST_CACHED_CODE}: ${PC_DYNAMIC_ST_JSA}
276 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_ST_JSA} -XX:+ReplayTraining -XX:+StoreCachedCode \
277 	     -XX:CachedCodeFile=${PC_ST_CACHED_CODE} -XX:CachedCodeMaxSize=512M ${UNPACKED_CMDLINE} &> $@.out &
278 	$(wait-for-startup)
279 	$(exit-app)
280 	ls -l $@
281 
282 ${PC_LT_CACHED_CODE}: ${PC_DYNAMIC_LT_JSA}
283 	${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_LT_JSA} -XX:+ReplayTraining -XX:+StoreCachedCode \
284 	     -Xlog:scc,cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=$@.log \
285 	     -XX:CachedCodeFile=${PC_LT_CACHED_CODE} -XX:CachedCodeMaxSize=512M ${UNPACKED_CMDLINE} &> $@.out &
286 	$(wait-for-startup)
287 	$(run-jmeter)
288 	$(exit-app)
289 	ls -l $@
290 
291 ${PC_CDS_PREIMAGE}: ${PC_APP_UNPACKED}
292 	rm -f ${PC_CDS_PREIMAGE} ${PC_CDS}
293 	${PREMAIN_JAVA} -XX:+AOTClassLinking \
294                -XX:+ArchiveReflectionData \
295                -XX:+ArchiveDynamicProxies -XX:+ArchiveLoaderLookupCache -XX:CachedCodeMaxSize=512M \
296                -XX:+UnlockDiagnosticVMOptions -XX:+CDSManualFinalImage -XX:CacheDataStore=${PC_CDS} \
297                -Xlog:cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=$@.log \
298                ${UNPACKED_CMDLINE} &> $@.out &
299 	$(wait-for-startup)
300 	$(run-jmeter)
301 	$(exit-app)
302 	ls -l $@
303 
304 ${PC_CDS}: ${PC_CDS_PREIMAGE}
305 	rm -f ${PC_CDS}
306 	${PREMAIN_JAVA} -XX:+AOTClassLinking -XX:CachedCodeMaxSize=512M \
307 	       -XX:+UnlockDiagnosticVMOptions -XX:CDSPreimage=${PC_CDS_PREIMAGE} -XX:CacheDataStore=${PC_CDS} \
308 	       -Xlog:scc,cds=debug,cds+class=debug,cds+heap=warning,cds+resolve=debug:file=$@.log \
309 	       -XX:-AssemblyStepInlining \
310 	       ${UNPACKED_CMDLINE} &> $@.out
311 	ls -l $@
312 	ls -l $@.code
313 
314 warmup-bl: ${PC_DYNAMIC_BL_JSA} ${JMETER_BIN}
315 	time taskset -c "${APP_CPUS}" ${BL_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_BL_JSA} \
316 		${UNPACKED_CMDLINE} &> $@.out &
317 	$(wait-for-startup)
318 	$(run-jmeter)
319 	$(exit-app)
320 
321 # run with dynamic archive without training data
322 warmup-preload: ${PC_DYNAMIC_NOTRAINING_JSA} ${JMETER_BIN}
323 	time taskset -c "${APP_CPUS}" ${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_NOTRAINING_JSA} \
324 		${UNPACKED_CMDLINE} &> $@.out &
325 	$(wait-for-startup)
326 	$(run-jmeter)
327 	$(exit-app)
328 
329 # run with dynamic archive with startup training data
330 warmup-st: ${PC_DYNAMIC_ST_JSA} ${JMETER_BIN}
331 	time taskset -c "${APP_CPUS}" ${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_ST_JSA} -XX:+ReplayTraining \
332 		${UNPACKED_CMDLINE} &> $@.out &
333 	$(wait-for-startup)
334 	$(run-jmeter)
335 	$(exit-app)
336 
337 # run with dynamic archive with load training data
338 warmup-lt: ${PC_DYNAMIC_LT_JSA} ${JMETER_BIN}
339 	time taskset -c "${APP_CPUS}" ${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_LT_JSA} -XX:+ReplayTraining \
340 		${UNPACKED_CMDLINE} &> $@.out &
341 	$(wait-for-startup)
342 	$(run-jmeter)
343 	$(exit-app)
344 
345 # run with startup training data and aot code
346 warmup-st-aot: ${PC_ST_CACHED_CODE} ${JMETER_BIN}
347 	time taskset -c "${APP_CPUS}" ${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_ST_JSA} -XX:+ReplayTraining -XX:+LoadCachedCode \
348 		-XX:CachedCodeFile=${PC_ST_CACHED_CODE} ${UNPACKED_CMDLINE} &> $@.out &
349 	$(wait-for-startup)
350 	$(run-jmeter)
351 	$(exit-app)
352 
353 # run with load training data and aot code
354 warmup-lt-aot: ${PC_LT_CACHED_CODE} ${JMETER_BIN}
355 	time taskset -c "${APP_CPUS}" ${PREMAIN_JAVA} -XX:SharedArchiveFile=${PC_DYNAMIC_LT_JSA} -XX:+ReplayTraining -XX:+LoadCachedCode \
356 		-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:-TraceDeoptimization \
357 		-Xlog:init -XX:CachedCodeFile=${PC_LT_CACHED_CODE} ${UNPACKED_CMDLINE} &> $@.out &
358 	$(wait-for-startup)
359 	$(run-jmeter)
360 	$(exit-app)
361 
362 # run with new single-step workflow
363 warmup-lt-aot-new: ${PC_CDS}
364 	time taskset -c "${APP_CPUS}" ${PREMAIN_JAVA} -XX:CacheDataStore=${PC_CDS} \
365 	       -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation \
366 	       -Xlog:init ${UNPACKED_CMDLINE} &> $@.out &
367 	$(wait-for-startup)
368 	$(run-jmeter)
369 	$(exit-app)
370 
371 run: warmup-bl warmup-preload warmup-st warmup-lt warmup-st-aot warmup-lt-aot warmup-lt-aot-new
372 
373 run17: ${PC_APP_UNPACKED}
374 	time ${JDK17_JAVA} ${UNPACKED_CMDLINE} &> $@.out &
375 	$(wait-for-startup)
376 	$(exit-app)
377 
378 
379 clean: clean0
380 	rm -rf *~ ${PC_REPO}
381 
382 # clean the the leyden artifacts
383 clean0:
384 	rm -fv spring-petclinic.* *.out tput-*.log app.pid