From 683a7be5b085f13a333eb4585b215d77696a766a Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 26 Aug 2021 18:09:12 +0200 Subject: [PATCH 1/3] delay Graal runtime initialization in jargraal until Graal compiler initialization --- .../hotspot/HotSpotGraalCompilerFactory.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java index 61a4e6c41428..facc8cd925ba 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java @@ -81,8 +81,39 @@ public String getCompilerName() { */ private IllegalArgumentException optionsFailure; + private volatile boolean initialized; + + private void ensureInitialized() { + if (!initialized) { + synchronized (this) { + if (!initialized) { + initialize(); + initialized = true; + } + } + } + } + @Override public void onSelection() { + if (Services.IS_IN_NATIVE_IMAGE) { + // When instantiating a JVMCI runtime in the libgraal heap there's no + // point in delaying HotSpotGraalRuntime initialization as it + // is very fast (it's compiled and does no class loading) and will + // usually be done immediately after this call anyway (i.e. in a + // Graal-as-JIT configuration). + initialize(); + initialized = true; + } else { + // When instantiating a JVMCI runtime in the HotSpot heap, initialization + // of a HotSpotGraalRuntime is deferred until a compiler instance is + // requested. This avoids extra class loading when the JMX code in libgraal + // (i.e. MBeanProxy) calls back into HotSpot. The HotSpot side of this call + // only needs a few Graal classes (namely LibGraalScope and kin). + } + } + + private void initialize() { JVMCIVersionCheck.check(Services.getSavedProperties(), false); assert options == null : "cannot select " + getClass() + " service more than once"; try { @@ -121,6 +152,7 @@ private static void initializeGraalCompilePolicyFields(OptionValues options) { @Override public void printProperties(PrintStream out) { + ensureInitialized(); out.println("[Graal properties]"); if (optionsFailure != null) { System.err.printf("Error parsing Graal options: %s%n", optionsFailure.getMessage()); @@ -145,6 +177,7 @@ static class Options { @Override public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) { + ensureInitialized(); HotSpotJVMCIRuntime hsRuntime = (HotSpotJVMCIRuntime) runtime; if (optionsFailure != null) { System.err.printf("Error parsing Graal options: %s%nError: A fatal exception has occurred. Program will exit.%n", optionsFailure.getMessage()); From 0326187173940aa66b8326c875dd61a68f3bf66c Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 30 Aug 2021 10:03:13 +0200 Subject: [PATCH 2/3] don't compare against newest VM image input if there is none --- sdk/mx.sdk/mx_sdk_vm_impl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 4f2ba8f4d927..ad437d0791f8 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -797,7 +797,7 @@ def needsUpdate(self, newestInput): output = self.get_output() if exists(output): ts = mx.TimeStampFile(output) - if ts.isOlderThan(newestInput): + if newestInput and ts.isOlderThan(newestInput): return "{} is older than {}".format(ts, newestInput) else: return None From 693c29700a7525b51b3a4d897dc57d259ca2fc1b Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 31 Aug 2021 14:50:12 +0200 Subject: [PATCH 3/3] only use separate thread to initialize first HotSpotGraalRuntimeMBean in VM process --- .../LibGraalHotSpotGraalManagement.java | 13 +++++++++--- .../management/libgraal/MBeanProxy.java | 21 +++++++++++-------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/LibGraalHotSpotGraalManagement.java b/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/LibGraalHotSpotGraalManagement.java index 784f007e6302..ee34501cb1e0 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/LibGraalHotSpotGraalManagement.java +++ b/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/LibGraalHotSpotGraalManagement.java @@ -39,6 +39,7 @@ import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; +import org.graalvm.word.Pointer; /** * Dynamically registers a {@link HotSpotGraalRuntimeMBean}s created in libgraal heap with an @@ -64,8 +65,8 @@ static class Options { /** * Creates a {@link HotSpotGraalRuntimeMBean} for given {@code runtime}. It first defines the * required classes in the HotSpot heap and starts the factory thread. Then it creates a - * {@link HotSpotGraalRuntimeMBean} for given {@code runtime} and notifies the factory thread - * about a new pending registration. + * {@link HotSpotGraalRuntimeMBean} for {@code runtime} and notifies the factory thread about a + * new pending registration. * * @param runtime the runtime to create {@link HotSpotGraalRuntimeMBean} for * @param config the configuration used to obtain the {@code _jni_environment} offset @@ -75,7 +76,13 @@ public void initialize(HotSpotGraalRuntime runtime, GraalHotSpotVMConfig config) int delay = Options.LibGraalManagementDelay.getValue(runtime.getOptions()); if (delay < 0) { return; - } else if (delay == 0) { + } + Pointer defineClassesStatePointer = getDefineClassesStatePointer(); + long defineClassesState = defineClassesStatePointer.readLong(0); + if (delay == 0 || defineClassesState == HS_CLASSES_DEFINED) { + // No delay or this is not the first Graal runtime to be initialized + // in the process. As such there's no need to use a separate thread + // to create the HotSpotGraalRuntimeMBean. initialize0(runtime, config); } else { Thread t = new GraalServiceThread(LibGraalHotSpotGraalManagement.class.getSimpleName() + "-init", new Runnable() { diff --git a/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/MBeanProxy.java b/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/MBeanProxy.java index a5c0b5e1c592..518612025f33 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/MBeanProxy.java +++ b/compiler/src/org.graalvm.compiler.hotspot.management.libgraal/src/org/graalvm/compiler/hotspot/management/libgraal/MBeanProxy.java @@ -92,6 +92,12 @@ class MBeanProxy { private static final ClassData HS_ENTRYPOINTS_CLASS = ClassData.create(JMXFromLibGraalEntryPoints.class); private static final ClassData HS_AGGREGATED_MEMORY_POOL_BEAN_CLASS = ClassData.create(AggregatedMemoryPoolBean.class); + // Values for the global word used to synchronize definition + // of the above classes in the HotSpot heap + static final long HS_CLASSES_UNDEFINED = 0L; + static final long HS_CLASSES_DEFINING = 1L; + static final long HS_CLASSES_DEFINED = 2L; + /** * Pending MBeans registrations on HotSpot side. * @@ -341,23 +347,20 @@ private static void runGuarded(Pointer barrier, Runnable defineAction, Runnable if (barrier.isNull()) { throw new IllegalStateException("Missing substitution for MBeanProxy.defineClassesInHotSpot"); } - final long undefined = 0L; - final long defining = 1L; - final long defined = 2L; long defineClassState = barrier.readLong(0); - if (defineClassState == defined) { + if (defineClassState == HS_CLASSES_DEFINED) { loadAction.run(); } else { while (true) { defineClassState = barrier.readLong(0); - if (defineClassState == undefined) { - if (barrier.compareAndSwapLong(0, undefined, defining, ANY_LOCATION) == undefined) { + if (defineClassState == HS_CLASSES_UNDEFINED) { + if (barrier.compareAndSwapLong(0, HS_CLASSES_UNDEFINED, HS_CLASSES_DEFINING, ANY_LOCATION) == HS_CLASSES_UNDEFINED) { defineAction.run(); - barrier.writeLong(0, defined); + barrier.writeLong(0, HS_CLASSES_DEFINED); break; } } else { - if (defineClassState == defined) { + if (defineClassState == HS_CLASSES_DEFINED) { loadAction.run(); break; } @@ -429,7 +432,7 @@ private static void unregister() { /** * Gets a pointer to a global word used as spin lock for safely defining classes in HotSpot. */ - private static Pointer getDefineClassesStatePointer() { + static Pointer getDefineClassesStatePointer() { // Substituted by Target_org_graalvm_compiler_hotspot_management_libgraal_MBeanProxy return WordFactory.nullPointer(); }