@@ -277,6 +277,50 @@ def libpythonvm_build_args():
277
277
return build_args
278
278
279
279
280
+ def graalpy_native_pgo_build_and_test (args ):
281
+ """
282
+ Builds a PGO-instrumented GraalPy native standalone, runs the unittests to generate a profile,
283
+ then builds a PGO-optimized GraalPy native standalone with the collected profile.
284
+ The profile file will be named 'default.iprof' in native image build directory.
285
+ """
286
+ import tempfile
287
+
288
+ with set_env (GRAALPY_PGO_PROFILE = "" ):
289
+ mx .log (mx .colorize ("[PGO] Building PGO-instrumented native image" , color = "yellow" ))
290
+ native_bin = graalpy_standalone ('native' , enterprise = True , build = True )
291
+
292
+ mx .log (mx .colorize ("[PGO] Instrumented build complete." , color = "yellow" ))
293
+
294
+ mx .log (mx .colorize (f"[PGO] Running graalpytest with instrumented binary: { native_bin } " , color = "yellow" ))
295
+ with tempfile .TemporaryDirectory () as d :
296
+ with set_env (
297
+ GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS = "true" ,
298
+ GRAAL_PYTHON_VM_ARGS = f"--vm.XX:ProfilesDumpFile={ os .path .join (d , '$UUID$.iprof' )} "
299
+ ):
300
+ graalpytest (["--python" , native_bin , "." ])
301
+ iprof_path = os .path .join (SUITE .dir , 'default.iprof' )
302
+
303
+ mx .run ([
304
+ os .path .join (
305
+ graalvm_jdk (enterprise = True ),
306
+ "bin" ,
307
+ f"native-image-configure{ '.exe' if mx .is_windows () else '' } " ,
308
+ ),
309
+ "merge-pgo-profiles" ,
310
+ f"--input-dir={ d } " ,
311
+ f"--output-file={ iprof_path } "
312
+ ])
313
+
314
+ if not os .path .isfile (iprof_path ):
315
+ mx .abort (f"[PGO] Could not find profile file at expected location: { iprof_path } " )
316
+
317
+ with set_env (GRAALPY_PGO_PROFILE = iprof_path ):
318
+ mx .log (mx .colorize ("[PGO] Building optimized native image with collected profile" , color = "yellow" ))
319
+ native_bin = graalpy_standalone ('native' , enterprise = True , build = True )
320
+
321
+ mx .log (mx .colorize (f"[PGO] Optimized PGO build complete: { native_bin } " , color = "yellow" ))
322
+
323
+
280
324
def full_python (args , env = None ):
281
325
"""Run python from standalone build (unless kwargs are given). Does not build GraalPython sources automatically."""
282
326
@@ -667,6 +711,16 @@ def graalpy_standalone_home(standalone_type, enterprise=False, dev=False, build=
667
711
if BUILD_NATIVE_IMAGE_WITH_ASSERTIONS :
668
712
mx_args .append ("--extra-image-builder-argument=-ea" )
669
713
714
+ pgo_profile = os .environ .get ("GRAALPY_PGO_PROFILE" )
715
+ if pgo_profile is not None :
716
+ if not enterprise or standalone_type != "native" :
717
+ mx .abort ("PGO is only supported on enterprise NI" )
718
+ if pgo_profile :
719
+ mx_args .append (f"--extra-image-builder-argument=--pgo={ pgo_profile } " )
720
+ mx_args .append (f"--extra-image-builder-argument=-H:+PGOPrintProfileQuality" )
721
+ else :
722
+ mx_args .append (f"--extra-image-builder-argument=--pgo-instrument" )
723
+
670
724
if mx_gate .get_jacoco_agent_args () or (build and not DISABLE_REBUILD ):
671
725
mx_build_args = mx_args
672
726
if BYTECODE_DSL_INTERPRETER :
@@ -913,7 +967,9 @@ def graalpytest(args):
913
967
python_binary = graalpy_standalone_native ()
914
968
elif 'graalpy' in os .path .basename (python_binary ) or 'mxbuild' in python_binary :
915
969
is_graalpy = True
916
- gp_args = ["--vm.ea" , "--vm.esa" , "--experimental-options=true" , "--python.EnableDebuggingBuiltins" ]
970
+ gp_args = ["--experimental-options=true" , "--python.EnableDebuggingBuiltins" ]
971
+ if env .get ("GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS" ) != "true" :
972
+ gp_args += ["--vm.ea" , "--vm.esa" ]
917
973
mx .log (f"Executable seems to be GraalPy, prepending arguments: { gp_args } " )
918
974
python_args += gp_args
919
975
if is_graalpy and BYTECODE_DSL_INTERPRETER :
@@ -2562,4 +2618,5 @@ def run_downstream_test(args):
2562
2618
'graalpy-jmh' : [graalpy_jmh , '' ],
2563
2619
'deploy-local-maven-repo' : [deploy_local_maven_repo_wrapper , '' ],
2564
2620
'downstream-test' : [run_downstream_test , '' ],
2621
+ 'python-native-pgo' : [graalpy_native_pgo_build_and_test , 'Build PGO-instrumented native image, run tests, then build PGO-optimized native image' ],
2565
2622
})
0 commit comments