From 6f7c278c06b8a6aa9f1ab9161a94c698cdb402c1 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 19 May 2026 14:15:45 +0200 Subject: [PATCH 1/5] [GR-67905] Save host inlining log for PGO profile job --- ci.jsonnet | 1 + mx.graalpython/mx_graalpython.py | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ci.jsonnet b/ci.jsonnet index 22a08ec2fc..493cf251e8 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -241,6 +241,7 @@ logs+: [ "default.iprof.gz", "default.lcov", + "host-inlining.txt", ], }), }), diff --git a/mx.graalpython/mx_graalpython.py b/mx.graalpython/mx_graalpython.py index 8392bc9d86..9a674fc80d 100644 --- a/mx.graalpython/mx_graalpython.py +++ b/mx.graalpython/mx_graalpython.py @@ -411,6 +411,10 @@ def graalpy_native_pgo_build_and_test(args=None): if mx_sdk_vm_ng.get_bootstrap_graalvm_version() < mx.VersionSpec("25.0"): mx.abort("python-native-pgo not supported on GraalVM < 25") + host_inlining_log = Path(SUITE.dir) / "host-inlining.txt" + if host_inlining_log.exists(): + host_inlining_log.unlink() + with set_env(GRAALPY_PGO_PROFILE=""): mx.log(mx.colorize("[PGO] Building PGO-instrumented native image", color="yellow")) build_home = graalpy_standalone_home('native', enterprise=True, build=True) @@ -469,11 +473,15 @@ def graalpy_native_pgo_build_and_test(args=None): if not os.path.isfile(iprof_path): mx.abort(f"[PGO] Could not find profile file at expected location: {iprof_path}") - with set_env(GRAALPY_PGO_PROFILE=str(iprof_path)): + with set_env(GRAALPY_PGO_PROFILE=str(iprof_path), GRAALPY_HOST_INLINING_LOG=str(host_inlining_log)): mx.log(mx.colorize("[PGO] Building optimized native image with collected profile", color="yellow")) native_bin = graalpy_standalone('native', enterprise=True, build=True) mx.log(mx.colorize(f"[PGO] Optimized PGO build complete: {native_bin}", color="yellow")) + if host_inlining_log.exists(): + mx.log(mx.colorize(f"[PGO] Host inlining log at: {host_inlining_log}", color="yellow")) + else: + mx.warn(f"[PGO] Host inlining log was not produced at expected location: {host_inlining_log}") iprof_gz_path = str(iprof_path) + '.gz' with open(iprof_path, 'rb') as f_in, gzip.open(iprof_gz_path, 'wb') as f_out: @@ -948,6 +956,14 @@ def graalpy_standalone_home(standalone_type, enterprise=False, dev=False, build= mx_args.append(f"--extra-image-builder-argument=--pgo={pgo_profile}") mx_args.append(f"--extra-image-builder-argument=-H:+UnlockExperimentalVMOptions") mx_args.append(f"--extra-image-builder-argument=-H:+PGOPrintProfileQuality") + if host_inlining_log := os.environ.get("GRAALPY_HOST_INLINING_LOG"): + mx_args.extend([ + f"--extra-image-builder-argument=-H:Log=HostInliningPhase,~CanonicalizerPhase,~GraphBuilderPhase", + f"--extra-image-builder-argument=-H:+TruffleHostInliningPrintExplored", + f"--extra-image-builder-argument=-H:MethodFilter=com.oracle.graal.python.*.*", + f"--extra-image-builder-argument=-H:-UnlockExperimentalVMOptions", + f"--extra-image-builder-argument=-Dgraal.LogFile={host_inlining_log}", + ]) else: mx_args.append(f"--extra-image-builder-argument=--pgo-instrument") mx_args.append(f"--extra-image-builder-argument=-H:+UnlockExperimentalVMOptions") From fb39b96a8d0b46ab6e99b998fa8a0a7b7c17a45a Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 19 May 2026 18:07:12 +0200 Subject: [PATCH 2/5] [GR-67905] Gzip host inlining log artifact --- ci.jsonnet | 2 +- mx.graalpython/mx_graalpython.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ci.jsonnet b/ci.jsonnet index 493cf251e8..a6a799a484 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -241,7 +241,7 @@ logs+: [ "default.iprof.gz", "default.lcov", - "host-inlining.txt", + "host-inlining.txt.gz", ], }), }), diff --git a/mx.graalpython/mx_graalpython.py b/mx.graalpython/mx_graalpython.py index 9a674fc80d..d56b2022d2 100644 --- a/mx.graalpython/mx_graalpython.py +++ b/mx.graalpython/mx_graalpython.py @@ -412,8 +412,11 @@ def graalpy_native_pgo_build_and_test(args=None): mx.abort("python-native-pgo not supported on GraalVM < 25") host_inlining_log = Path(SUITE.dir) / "host-inlining.txt" + host_inlining_log_gz = Path(str(host_inlining_log) + ".gz") if host_inlining_log.exists(): host_inlining_log.unlink() + if host_inlining_log_gz.exists(): + host_inlining_log_gz.unlink() with set_env(GRAALPY_PGO_PROFILE=""): mx.log(mx.colorize("[PGO] Building PGO-instrumented native image", color="yellow")) @@ -480,6 +483,10 @@ def graalpy_native_pgo_build_and_test(args=None): mx.log(mx.colorize(f"[PGO] Optimized PGO build complete: {native_bin}", color="yellow")) if host_inlining_log.exists(): mx.log(mx.colorize(f"[PGO] Host inlining log at: {host_inlining_log}", color="yellow")) + with open(host_inlining_log, 'rb') as f_in, gzip.open(host_inlining_log_gz, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + host_inlining_log.unlink() + mx.log(mx.colorize(f"[PGO] Gzipped host inlining log at: {host_inlining_log_gz}", color="yellow")) else: mx.warn(f"[PGO] Host inlining log was not produced at expected location: {host_inlining_log}") From 16d8722f1df60ac7b12ffef086e2c3af639046ee Mon Sep 17 00:00:00 2001 From: stepan Date: Fri, 22 May 2026 11:26:38 +0200 Subject: [PATCH 3/5] Disable cached generation for object slots lookup --- .../graal/python/builtins/objects/type/TpSlots.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java index d0d730189b..a8dc200a74 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java @@ -229,7 +229,6 @@ import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.DenyReplace; import com.oracle.truffle.api.nodes.Node; @@ -2026,24 +2025,15 @@ public static GetCachedTpSlotsNode getUncached() { } @GenerateInline(inlineByDefault = true) - @GenerateCached + @GenerateCached(false) @GenerateUncached public abstract static class GetObjectSlotsNode extends Node { public abstract TpSlots execute(Node inliningTarget, Object pythonObject); - public final TpSlots executeCached(Object pythonObject) { - return execute(this, pythonObject); - } - public static TpSlots executeUncached(Object pythonObject) { return GetObjectSlotsNodeGen.getUncached().execute(null, pythonObject); } - @NeverDefault - public static GetObjectSlotsNode create() { - return GetObjectSlotsNodeGen.create(); - } - // Note: it seems that switching the GetClassNode with an adhoc GetClassNode variant that // does not have any inline caches does not change peak at least for micro:if-polymorph // TODO: verify this on all benchmarks and get rid of the IC if possible From f23c605162a729541e767993b6c03f6b42c218bf Mon Sep 17 00:00:00 2001 From: stepan Date: Fri, 22 May 2026 13:01:48 +0200 Subject: [PATCH 4/5] Disable cached generation for inline-only nodes --- .../oracle/graal/python/builtins/modules/TRegexUtil.java | 6 +++--- .../graal/python/builtins/modules/io/BufferedIONodes.java | 2 +- .../graal/python/builtins/objects/cext/capi/CExtNodes.java | 4 ++-- .../oracle/graal/python/builtins/objects/type/TpSlots.java | 6 +++--- .../oracle/graal/python/lib/PyEnterRecursiveCallNode.java | 2 +- .../graal/python/lib/PyLongAsLongAndOverflowNode.java | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TRegexUtil.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TRegexUtil.java index cdd0441fdc..34edb85a36 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TRegexUtil.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TRegexUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -91,8 +91,8 @@ private RegexResult() { private static final String NUMBER_OF_REGEX_RESULT_TYPES = "1"; - @GenerateCached - @GenerateInline(inlineByDefault = true) + @GenerateCached(false) + @GenerateInline @GenerateUncached public abstract static class InteropReadMemberNode extends Node { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java index f6de4820a8..7d120cf126 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java @@ -245,7 +245,7 @@ RawTellNode doIt(@Cached(inline = false) RawTellNode node) { } } - @GenerateInline(inlineByDefault = true) + @GenerateInline @GenerateCached(false) abstract static class RawTellIgnoreErrorNode extends PNodeWithContext { public abstract long execute(VirtualFrame frame, Node inliningTarget, PBuffered self); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java index 655b4cfa27..1015ab3357 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java @@ -535,8 +535,8 @@ static PComplex runGeneric(Node inliningTarget, Object value, * avoid eager and explicit conversion. */ @ImportStatic(PythonUtils.class) - @GenerateInline(inlineByDefault = true) - @GenerateCached + @GenerateInline + @GenerateCached(false) @GenerateUncached public abstract static class CastToNativeLongNode extends PNodeWithContext { public abstract long execute(Node inliningTarget, boolean arg); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java index a8dc200a74..4e99840aa5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java @@ -1990,8 +1990,8 @@ private static TpSlots initializeNativeSlots(PythonAbstractNativeObject nativeKl } } - @GenerateInline(inlineByDefault = true) - @GenerateCached + @GenerateInline + @GenerateCached(false) @ImportStatic(PGuards.class) public abstract static class GetCachedTpSlotsNode extends Node { public abstract TpSlots execute(Node inliningTarget, Object pythonClass); @@ -2024,7 +2024,7 @@ public static GetCachedTpSlotsNode getUncached() { } } - @GenerateInline(inlineByDefault = true) + @GenerateInline @GenerateCached(false) @GenerateUncached public abstract static class GetObjectSlotsNode extends Node { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyEnterRecursiveCallNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyEnterRecursiveCallNode.java index b8afef2b71..adda9f8a03 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyEnterRecursiveCallNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyEnterRecursiveCallNode.java @@ -62,7 +62,7 @@ * and {@code _Py_EnterRecursiveCall}. */ @GenerateUncached -@GenerateInline(inlineByDefault = true) +@GenerateInline @GenerateCached(false) public abstract class PyEnterRecursiveCallNode extends PNodeWithContext { protected abstract PythonThreadState execute(Node inliningTarget, TruffleString errorMessage, Object formatArg, boolean withFormatArg); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyLongAsLongAndOverflowNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyLongAsLongAndOverflowNode.java index 49ee94f203..e9450f292e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyLongAsLongAndOverflowNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyLongAsLongAndOverflowNode.java @@ -61,7 +61,7 @@ * {@link com.oracle.graal.python.util.OverflowException}. */ @GenerateUncached -@GenerateInline(inlineByDefault = true) +@GenerateInline @GenerateCached(false) public abstract class PyLongAsLongAndOverflowNode extends PNodeWithContext { From c1cb21fdba94a6cfca3331dde8161d6e89860f06 Mon Sep 17 00:00:00 2001 From: stepan Date: Fri, 22 May 2026 13:10:25 +0200 Subject: [PATCH 5/5] Disable cached generation for more inline-only nodes --- .../python/builtins/modules/io/BufferedIOMixinBuiltins.java | 4 ++-- .../graal/python/builtins/modules/io/BufferedIONodes.java | 2 +- .../graal/python/nodes/attributes/GetFixedAttributeNode.java | 2 +- .../MergedObjectTypeModuleGetFixedAttributeNode.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIOMixinBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIOMixinBuiltins.java index 5d8a1f3cbc..eb89c28eb9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIOMixinBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIOMixinBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -275,7 +275,7 @@ static long doit(VirtualFrame frame, PBuffered self, Object off, int whence, @Cached("create(T_SEEK)") CheckIsClosedNode checkIsClosedNode, @Cached BufferedIONodes.CheckIsSeekabledNode checkIsSeekabledNode, @Cached BufferedIONodes.AsOffNumberNode asOffNumberNode, - @Cached(inline = true) BufferedIONodes.SeekNode seekNode) { + @Cached BufferedIONodes.SeekNode seekNode) { checkIsClosedNode.execute(frame, self); checkIsSeekabledNode.execute(frame, self); long pos = asOffNumberNode.execute(frame, inliningTarget, off, TypeError); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java index 7d120cf126..a1835cbe60 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedIONodes.java @@ -337,7 +337,7 @@ protected static void readWrite(VirtualFrame frame, PBuffered self, * implementation of cpython/Modules/_io/bufferedio.c:_io__Buffered_seek_impl */ @GenerateInline - @GenerateCached + @GenerateCached(false) abstract static class SeekNode extends PNodeWithContext { public abstract long execute(VirtualFrame frame, Node inliningTarget, PBuffered self, long off, int whence); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/GetFixedAttributeNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/GetFixedAttributeNode.java index c7d4265fe6..4f06d56c5d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/GetFixedAttributeNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/GetFixedAttributeNode.java @@ -66,7 +66,7 @@ Object doIt(VirtualFrame frame, Object object, @Bind Node inliningTarget, @Cached GetClassNode getClassNode, @Cached GetCachedTpSlotsNode getSlotsNode, - @Cached(inline = true) MergedObjectTypeModuleGetFixedAttributeNode innerNode) { + @Cached MergedObjectTypeModuleGetFixedAttributeNode innerNode) { Object type = getClassNode.execute(inliningTarget, object); TpSlots slots = getSlotsNode.execute(inliningTarget, type); return innerNode.execute(frame, inliningTarget, object, key, type, slots); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/MergedObjectTypeModuleGetFixedAttributeNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/MergedObjectTypeModuleGetFixedAttributeNode.java index d74a71d49c..33ec150b59 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/MergedObjectTypeModuleGetFixedAttributeNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/MergedObjectTypeModuleGetFixedAttributeNode.java @@ -82,7 +82,7 @@ * inlining, but the caller is expected to keep its identity stable for the lifetime of the node. */ @GenerateInline -@GenerateCached +@GenerateCached(false) public abstract class MergedObjectTypeModuleGetFixedAttributeNode extends PNodeWithContext { public abstract Object execute(VirtualFrame frame, Node inliningTarget, Object object, TruffleString key, Object type, TpSlots slots);