diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index a11010892c34..b1b59e9ca543 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -22,6 +22,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-44216) Native Image is now shipped as part of the GraalVM JDK and thus no longer needs to be installed via `gu install native-image`. * (GR-44105) A warning is displayed when trying to generate debug info on macOS since that is not supported. It is now an error to use `-H:+StripDebugInfo` on macOS or `-H:-StripDebugInfo` on Windows since those values are not supported. * (GR-43966) Remove analysis options -H:AnalysisStatisticsFile and -H:ImageBuildStatisticsFile. Output files are now written to fixed subdirectories relative to image location (reports/image_build_statistics.json). +* (GR-38414) BellSoft implemented the `MemoryPoolMXBean` for the serial and epsilon GCs. * (GR-40641) Dynamic linking of AWT libraries on Linux. ## Version 22.3.0 diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java index fccc52eb5d1f..f5f8a4e14b4d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java @@ -26,7 +26,6 @@ import java.util.concurrent.atomic.AtomicBoolean; -import com.oracle.svm.core.heap.GCCause; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.nodes.PauseNode; import org.graalvm.nativeimage.Platform; @@ -36,6 +35,7 @@ import com.oracle.svm.core.SubstrateGCOptions; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.heap.GCCause; import com.oracle.svm.core.heap.PhysicalMemory; import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.jdk.UninterruptibleUtils; @@ -193,13 +193,21 @@ private void updateSizeParametersLocked(SizeParameters params, SizeParameters pr * but we must still ensure that computations can handle it (for example, no overflows). */ survivorSize = UnsignedUtils.min(survivorSize, params.maxSurvivorSize()); - edenSize = UnsignedUtils.min(edenSize, maxEdenSize()); + edenSize = UnsignedUtils.min(edenSize, getMaximumEdenSize()); oldSize = UnsignedUtils.min(oldSize, params.maxOldSize()); promoSize = UnsignedUtils.min(promoSize, params.maxOldSize()); } + @Override + public UnsignedWord getInitialEdenSize() { + guaranteeSizeParametersInitialized(); + return sizes.initialEdenSize; + } + + @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - protected UnsignedWord maxEdenSize() { + public UnsignedWord getMaximumEdenSize() { + guaranteeSizeParametersInitialized(); return alignDown(sizes.maxYoungSize.subtract(survivorSize.multiply(2))); } @@ -215,6 +223,18 @@ public UnsignedWord getMaximumYoungGenerationSize() { return sizes.maxYoungSize; } + @Override + public UnsignedWord getInitialSurvivorSize() { + guaranteeSizeParametersInitialized(); + return sizes.initialSurvivorSize; + } + + @Override + public UnsignedWord getMaximumSurvivorSize() { + guaranteeSizeParametersInitialized(); + return sizes.maxSurvivorSize(); + } + @Override public UnsignedWord getCurrentHeapCapacity() { assert VMOperation.isGCInProgress() : "use only during GC"; @@ -236,6 +256,18 @@ public UnsignedWord getYoungGenerationCapacity() { return edenSize.add(survivorSize); } + @Override + public UnsignedWord getInitialOldSize() { + guaranteeSizeParametersInitialized(); + return sizes.initialOldSize(); + } + + @Override + public UnsignedWord getMaximumOldSize() { + guaranteeSizeParametersInitialized(); + return sizes.maxOldSize(); + } + @Override public UnsignedWord getOldGenerationCapacity() { guaranteeSizeParametersInitialized(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractMemoryPoolMXBean.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractMemoryPoolMXBean.java new file mode 100644 index 000000000000..f2a23be29ba3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractMemoryPoolMXBean.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2023, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.genscavenge; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryType; +import java.lang.management.MemoryUsage; +import java.util.Arrays; + +import javax.management.ObjectName; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.heap.AbstractMXBean; +import com.oracle.svm.core.jdk.UninterruptibleUtils; + +import sun.management.Util; + +public abstract class AbstractMemoryPoolMXBean extends AbstractMXBean implements MemoryPoolMXBean { + + private final String name; + private final String[] managerNames; + protected final UninterruptibleUtils.AtomicUnsigned peakUsage = new UninterruptibleUtils.AtomicUnsigned(); + + private static final UnsignedWord UNDEFINED = WordFactory.zero(); + protected UnsignedWord initialValue = UNDEFINED; + + @Platforms(Platform.HOSTED_ONLY.class) + protected AbstractMemoryPoolMXBean(String name, String... managerNames) { + this.name = name; + this.managerNames = managerNames; + } + + UnsignedWord getInitialValue() { + if (initialValue.equal(UNDEFINED)) { + initialValue = computeInitialValue(); + } + return initialValue; + } + + abstract UnsignedWord computeInitialValue(); + + abstract UnsignedWord getMaximumValue(); + + abstract void afterCollection(GCAccounting accounting); + + MemoryUsage memoryUsage(UnsignedWord usedAndCommitted) { + return new MemoryUsage(getInitialValue().rawValue(), usedAndCommitted.rawValue(), usedAndCommitted.rawValue(), getMaximumValue().rawValue()); + } + + MemoryUsage memoryUsage(UnsignedWord used, UnsignedWord committed) { + return new MemoryUsage(getInitialValue().rawValue(), used.rawValue(), committed.rawValue(), getMaximumValue().rawValue()); + } + + @Override + public String getName() { + return name; + } + + @Override + public String[] getMemoryManagerNames() { + return Arrays.copyOf(managerNames, managerNames.length); + } + + @Override + public ObjectName getObjectName() { + return Util.newObjectName(ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",name=" + name); + } + + @Override + public MemoryType getType() { + return MemoryType.HEAP; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public boolean isUsageThresholdSupported() { + return false; + } + + @Override + public long getUsageThreshold() { + throw new UnsupportedOperationException("Usage threshold is not supported"); + } + + @Override + public void setUsageThreshold(long l) { + throw new UnsupportedOperationException("Usage threshold is not supported"); + } + + @Override + public boolean isUsageThresholdExceeded() { + throw new UnsupportedOperationException("Usage threshold is not supported"); + } + + @Override + public long getUsageThresholdCount() { + throw new UnsupportedOperationException("Usage threshold is not supported"); + } + + @Override + public boolean isCollectionUsageThresholdSupported() { + return false; + } + + @Override + public long getCollectionUsageThreshold() { + throw new UnsupportedOperationException("Collection usage threshold is not supported"); + } + + @Override + public void setCollectionUsageThreshold(long l) { + throw new UnsupportedOperationException("Collection usage threshold is not supported"); + } + + @Override + public boolean isCollectionUsageThresholdExceeded() { + throw new UnsupportedOperationException("Collection usage threshold is not supported"); + } + + @Override + public long getCollectionUsageThresholdCount() { + throw new UnsupportedOperationException("Collection usage threshold is not supported"); + } + + @Override + public void resetPeakUsage() { + peakUsage.set(WordFactory.zero()); + } + + void updatePeakUsage(UnsignedWord value) { + UnsignedWord current; + do { + current = peakUsage.get(); + } while (value.aboveThan(current) && !peakUsage.compareAndSet(current, value)); + } +} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java index fe3c3e78b945..9175c859012b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java @@ -270,7 +270,7 @@ protected void computeEdenSpaceSize(@SuppressWarnings("unused") boolean complete assert isAligned(desiredEdenSize); desiredEdenSize = minSpaceSize(desiredEdenSize); - UnsignedWord edenLimit = maxEdenSize(); + UnsignedWord edenLimit = getMaximumEdenSize(); if (desiredEdenSize.aboveThan(edenLimit)) { /* * If the policy says to get a larger eden but is hitting the limit, don't decrease diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java index 98377207f793..ae89d3740679 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java @@ -87,6 +87,16 @@ public void updateSizeParameters() { // Size parameters are recomputed from current values whenever they are queried } + @Override + public UnsignedWord getInitialEdenSize() { + return UNDEFINED; + } + + @Override + public UnsignedWord getMaximumEdenSize() { + return getMaximumYoungGenerationSize(); + } + @Override public final UnsignedWord getMaximumHeapSize() { long runtimeValue = SubstrateGCOptions.MaxHeapSize.getValue(); @@ -146,6 +156,16 @@ public final UnsignedWord getMinimumHeapSize() { return result; } + @Override + public UnsignedWord getInitialSurvivorSize() { + return UNDEFINED; + } + + @Override + public UnsignedWord getMaximumSurvivorSize() { + return WordFactory.zero(); + } + @Override public UnsignedWord getSurvivorSpacesCapacity() { return WordFactory.zero(); @@ -156,6 +176,11 @@ public UnsignedWord getYoungGenerationCapacity() { return getMaximumYoungGenerationSize(); } + @Override + public UnsignedWord getInitialOldSize() { + return UNDEFINED; + } + @Override public UnsignedWord getOldGenerationCapacity() { UnsignedWord heapCapacity = getCurrentHeapCapacity(); @@ -166,6 +191,11 @@ public UnsignedWord getOldGenerationCapacity() { return heapCapacity.subtract(youngCapacity); } + @Override + public UnsignedWord getMaximumOldSize() { + return getOldGenerationCapacity(); + } + @Override public final UnsignedWord getMaximumFreeAlignedChunksSize() { return getMaximumYoungGenerationSize(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java index fff7b6482740..1d11025ef0f7 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java @@ -27,6 +27,7 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.heap.GCCause; @@ -36,6 +37,8 @@ /** The interface for a garbage collection policy. All sizes are in bytes. */ public interface CollectionPolicy { + UnsignedWord UNDEFINED = WordFactory.unsigned(-1); + @Platforms(Platform.HOSTED_ONLY.class) static String getInitialPolicyName() { if (SubstrateOptions.UseEpsilonGC.getValue()) { @@ -143,6 +146,11 @@ static boolean shouldCollectYoungGenSeparately(boolean defaultValue) { */ UnsignedWord getCurrentHeapCapacity(); + /** May be {@link #UNDEFINED}. */ + UnsignedWord getInitialEdenSize(); + + UnsignedWord getMaximumEdenSize(); + /** * The hard limit for the size of the entire heap. Exceeding this limit triggers an * {@link OutOfMemoryError}. @@ -158,6 +166,11 @@ static boolean shouldCollectYoungGenSeparately(boolean defaultValue) { /** The minimum heap size, for inclusion in diagnostic output. */ UnsignedWord getMinimumHeapSize(); + /** May be {@link #UNDEFINED}. */ + UnsignedWord getInitialSurvivorSize(); + + UnsignedWord getMaximumSurvivorSize(); + /** * The total capacity of all survivor-from spaces of all ages, equal to the size of all * survivor-to spaces of all ages. In other words, when copying during a collection, up to 2x @@ -168,9 +181,14 @@ static boolean shouldCollectYoungGenSeparately(boolean defaultValue) { /** The capacity of the young generation, comprising the eden and survivor spaces. */ UnsignedWord getYoungGenerationCapacity(); + /** May be {@link #UNDEFINED}. */ + UnsignedWord getInitialOldSize(); + /** The capacity of the old generation. */ UnsignedWord getOldGenerationCapacity(); + UnsignedWord getMaximumOldSize(); + /** * The maximum number of bytes that should be kept readily available for allocation or copying * during collections. @@ -189,5 +207,4 @@ static boolean shouldCollectYoungGenSeparately(boolean defaultValue) { /** Called before the end of a collection, in the safepoint operation. */ void onCollectionEnd(boolean completeCollection, GCCause cause); - } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java index e556ce773b81..128df06b6087 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java @@ -50,6 +50,7 @@ public final class GCAccounting { private boolean lastIncrementalCollectionOverflowedSurvivors = false; /* Before and after measures. */ + private UnsignedWord edenChunkBytesBefore = WordFactory.zero(); private UnsignedWord youngChunkBytesBefore = WordFactory.zero(); private UnsignedWord youngChunkBytesAfter = WordFactory.zero(); private UnsignedWord oldChunkBytesBefore = WordFactory.zero(); @@ -104,6 +105,10 @@ public UnsignedWord getOldGenerationAfterChunkBytes() { return oldChunkBytesAfter; } + UnsignedWord getEdenChunkBytesBefore() { + return edenChunkBytesBefore; + } + UnsignedWord getYoungChunkBytesBefore() { return youngChunkBytesBefore; } @@ -125,6 +130,7 @@ void beforeCollection(boolean completeCollection) { /* Gather some space statistics. */ HeapImpl heap = HeapImpl.getHeapImpl(); YoungGeneration youngGen = heap.getYoungGeneration(); + edenChunkBytesBefore = youngGen.getEden().getChunkBytes(); youngChunkBytesBefore = youngGen.getChunkBytes(); /* This is called before the collection, so OldSpace is FromSpace. */ Space oldSpace = heap.getOldGeneration().getFromSpace(); @@ -140,7 +146,8 @@ void beforeCollection(boolean completeCollection) { if (!completeCollection) { lastIncrementalCollectionOverflowedSurvivors = false; } - trace.string(" youngChunkBytesBefore: ").unsigned(youngChunkBytesBefore) + trace.string(" edenChunkBytesBefore: ").unsigned(edenChunkBytesBefore) + .string(" youngChunkBytesBefore: ").unsigned(youngChunkBytesBefore) .string(" oldChunkBytesBefore: ").unsigned(oldChunkBytesBefore); trace.string("]").newline(); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index 58bb66d00afc..38d58ce2587d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -43,15 +43,14 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.MemoryWalker; +import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.SubstrateGCOptions; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.UnmanagedMemoryUtil; -import com.oracle.svm.core.AlwaysInline; -import com.oracle.svm.core.NeverInline; -import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.UnmanagedMemoryUtil; import com.oracle.svm.core.c.NonmovableArray; import com.oracle.svm.core.code.CodeInfo; import com.oracle.svm.core.code.CodeInfoAccess; @@ -74,6 +73,7 @@ import com.oracle.svm.core.heap.OutOfMemoryUtil; import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceMapIndex; +import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.heap.RuntimeCodeCacheCleaner; import com.oracle.svm.core.heap.VMOperationInfos; import com.oracle.svm.core.jdk.RuntimeSupport; @@ -294,6 +294,8 @@ private boolean doCollectOnce(GCCause cause, long requestingNanoTime, boolean co accounting.afterCollection(completeCollection, collectionTimer); policy.onCollectionEnd(completeCollection, cause); + GenScavengeMemoryPoolMXBeans.notifyAfterCollection(accounting); + UnsignedWord usedBytes = getChunkBytes(); UnsignedWord freeBytes = policy.getCurrentHeapCapacity().subtract(usedBytes); ReferenceObjectProcessing.afterCollection(freeBytes); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GenScavengeMemoryPoolMXBeans.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GenScavengeMemoryPoolMXBeans.java new file mode 100644 index 000000000000..4e0daf2c7dc0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GenScavengeMemoryPoolMXBeans.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2023, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.genscavenge; + +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryUsage; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.util.VMError; + +public class GenScavengeMemoryPoolMXBeans { + + private static final String YOUNG_GEN_SCAVENGER = "young generation scavenger"; + private static final String COMPLETE_SCAVENGER = "complete scavenger"; + private static final String EPSILON_SCAVENGER = "epsilon scavenger"; + + private static AbstractMemoryPoolMXBean[] mxBeans; + + @Platforms(Platform.HOSTED_ONLY.class) + public static MemoryPoolMXBean[] createMemoryPoolMXBeans() { + if (SubstrateOptions.UseSerialGC.getValue()) { + mxBeans = new AbstractMemoryPoolMXBean[]{ + new EdenMemoryPoolMXBean(YOUNG_GEN_SCAVENGER, COMPLETE_SCAVENGER), + new SurvivorMemoryPoolMXBean(YOUNG_GEN_SCAVENGER, COMPLETE_SCAVENGER), + new OldGenerationMemoryPoolMXBean(COMPLETE_SCAVENGER) + }; + } else { + assert SubstrateOptions.UseEpsilonGC.getValue(); + mxBeans = new AbstractMemoryPoolMXBean[]{ + new EpsilonMemoryPoolMXBean(EPSILON_SCAVENGER) + }; + } + return mxBeans; + } + + public static void notifyAfterCollection(GCAccounting accounting) { + for (AbstractMemoryPoolMXBean mxBean : mxBeans) { + mxBean.afterCollection(accounting); + } + } + + static final class EdenMemoryPoolMXBean extends AbstractMemoryPoolMXBean { + + @Platforms(Platform.HOSTED_ONLY.class) + EdenMemoryPoolMXBean(String... managerNames) { + super("eden space", managerNames); + } + + @Override + UnsignedWord computeInitialValue() { + return GCImpl.getPolicy().getInitialEdenSize(); + } + + @Override + UnsignedWord getMaximumValue() { + return GCImpl.getPolicy().getMaximumEdenSize(); + } + + @Override + void afterCollection(GCAccounting accounting) { + updatePeakUsage(accounting.getEdenChunkBytesBefore()); + } + + @Override + public MemoryUsage getUsage() { + return memoryUsage(getCurrentUsage()); + } + + @Override + public MemoryUsage getPeakUsage() { + updatePeakUsage(getCurrentUsage()); + return memoryUsage(peakUsage.get()); + } + + @Override + public MemoryUsage getCollectionUsage() { + return memoryUsage(WordFactory.zero()); + } + + private static UnsignedWord getCurrentUsage() { + return HeapImpl.getHeapImpl().getAccounting().getEdenUsedBytes(); + } + } + + static final class SurvivorMemoryPoolMXBean extends AbstractMemoryPoolMXBean { + + @Platforms(Platform.HOSTED_ONLY.class) + SurvivorMemoryPoolMXBean(String... managerNames) { + super("survivor space", managerNames); + } + + @Override + UnsignedWord computeInitialValue() { + return GCImpl.getPolicy().getInitialSurvivorSize(); + } + + @Override + UnsignedWord getMaximumValue() { + return GCImpl.getPolicy().getMaximumSurvivorSize(); + } + + @Override + void afterCollection(GCAccounting accounting) { + updatePeakUsage(accounting.getYoungChunkBytesAfter()); + } + + @Override + public MemoryUsage getUsage() { + return getCollectionUsage(); + } + + @Override + public MemoryUsage getPeakUsage() { + return memoryUsage(peakUsage.get()); + } + + @Override + public MemoryUsage getCollectionUsage() { + return memoryUsage(GCImpl.getGCImpl().getAccounting().getYoungChunkBytesAfter()); + } + } + + static final class OldGenerationMemoryPoolMXBean extends AbstractMemoryPoolMXBean { + + @Platforms(Platform.HOSTED_ONLY.class) + OldGenerationMemoryPoolMXBean(String... managerNames) { + super("old generation space", managerNames); + } + + @Override + UnsignedWord computeInitialValue() { + return GCImpl.getPolicy().getInitialOldSize(); + } + + @Override + UnsignedWord getMaximumValue() { + return GCImpl.getPolicy().getMaximumOldSize(); + } + + @Override + void afterCollection(GCAccounting accounting) { + updatePeakUsage(accounting.getOldGenerationAfterChunkBytes()); + } + + @Override + public MemoryUsage getUsage() { + return getCollectionUsage(); + } + + @Override + public MemoryUsage getPeakUsage() { + return memoryUsage(peakUsage.get()); + } + + @Override + public MemoryUsage getCollectionUsage() { + return memoryUsage(GCImpl.getGCImpl().getAccounting().getOldGenerationAfterChunkBytes()); + } + } + + static final class EpsilonMemoryPoolMXBean extends AbstractMemoryPoolMXBean { + + @Platforms(Platform.HOSTED_ONLY.class) + EpsilonMemoryPoolMXBean(String... managerNames) { + super("epsilon heap", managerNames); + } + + @Override + UnsignedWord computeInitialValue() { + return GCImpl.getPolicy().getMinimumHeapSize(); + } + + @Override + UnsignedWord getMaximumValue() { + return GCImpl.getPolicy().getMaximumHeapSize(); + } + + @Override + void afterCollection(GCAccounting accounting) { + throw VMError.shouldNotReachHere(); + } + + @Override + public MemoryUsage getUsage() { + HeapImpl heapImpl = HeapImpl.getHeapImpl(); + return memoryUsage(heapImpl.getUsedBytes(), heapImpl.getCommittedBytes()); + } + + @Override + public MemoryUsage getPeakUsage() { + return getUsage(); + } + + @Override + public MemoryUsage getCollectionUsage() { + return memoryUsage(WordFactory.zero()); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java index fbeddc93b71c..8216f42ead84 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.genscavenge.graal; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -39,6 +40,7 @@ import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.genscavenge.ChunkedImageHeapLayouter; import com.oracle.svm.core.genscavenge.CompleteGarbageCollectorMXBean; +import com.oracle.svm.core.genscavenge.GenScavengeMemoryPoolMXBeans; import com.oracle.svm.core.genscavenge.HeapImpl; import com.oracle.svm.core.genscavenge.HeapImplMemoryMXBean; import com.oracle.svm.core.genscavenge.ImageHeapInfo; @@ -92,7 +94,10 @@ public void duringSetup(DuringSetupAccess access) { ManagementSupport managementSupport = ManagementSupport.getSingleton(); managementSupport.addPlatformManagedObjectSingleton(java.lang.management.MemoryMXBean.class, new HeapImplMemoryMXBean()); + managementSupport.addPlatformManagedObjectList(java.lang.management.MemoryPoolMXBean.class, Arrays.asList(GenScavengeMemoryPoolMXBeans.createMemoryPoolMXBeans())); managementSupport.addPlatformManagedObjectList(com.sun.management.GarbageCollectorMXBean.class, Arrays.asList(new IncrementalGarbageCollectorMXBean(), new CompleteGarbageCollectorMXBean())); + /* Not supported yet. */ + managementSupport.addPlatformManagedObjectList(java.lang.management.BufferPoolMXBean.class, Collections.emptyList()); if (ImageSingletons.contains(PerfManager.class)) { ImageSingletons.lookup(PerfManager.class).register(createPerfData()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/AbstractMXBean.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/AbstractMXBean.java new file mode 100644 index 000000000000..c9e2a269cc98 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/AbstractMXBean.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2023, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.heap; + +import javax.management.MBeanNotificationInfo; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +public abstract class AbstractMXBean implements NotificationEmitter { + + protected static final long UNDEFINED_MEMORY_USAGE = -1L; + + @Override + public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { + } + + @Override + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { + } + + @Override + public void removeNotificationListener(NotificationListener listener) { + } + + @Override + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[0]; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/AbstractMemoryMXBean.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/AbstractMemoryMXBean.java index eca682c9d79f..f067c5c3ecc7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/AbstractMemoryMXBean.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/AbstractMemoryMXBean.java @@ -28,10 +28,6 @@ import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; -import javax.management.MBeanNotificationInfo; -import javax.management.NotificationEmitter; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; import javax.management.ObjectName; import org.graalvm.nativeimage.Platform; @@ -48,8 +44,7 @@ import sun.management.Util; -public abstract class AbstractMemoryMXBean implements MemoryMXBean, NotificationEmitter { - protected static final long UNDEFINED_MEMORY_USAGE = -1L; +public abstract class AbstractMemoryMXBean extends AbstractMXBean implements MemoryMXBean { private final MemoryMXBeanCodeInfoVisitor codeInfoVisitor; @@ -93,23 +88,6 @@ public void gc() { System.gc(); } - @Override - public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { - } - - @Override - public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { - } - - @Override - public void removeNotificationListener(NotificationListener listener) { - } - - @Override - public MBeanNotificationInfo[] getNotificationInfo() { - return new MBeanNotificationInfo[0]; - } - private static final class MemoryMXBeanCodeInfoVisitor implements CodeInfoVisitor { private UnsignedWord runtimeCodeInfoSize; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java index e969b1036e31..ca96c3bc827e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java @@ -141,12 +141,6 @@ public final class ManagementSupport implements ThreadListener { addPlatformManagedObjectSingleton(java.lang.management.CompilationMXBean.class, compilationMXBean); addPlatformManagedObjectSingleton(java.lang.management.RuntimeMXBean.class, runtimeMXBean); addPlatformManagedObjectSingleton(com.sun.management.ThreadMXBean.class, threadMXBean); - /* - * The following platform objects must be registered as existing and valid, even though we - * do not have an implementation yet. - */ - addPlatformManagedObjectList(java.lang.management.MemoryPoolMXBean.class, Collections.emptyList()); - addPlatformManagedObjectList(java.lang.management.BufferPoolMXBean.class, Collections.emptyList()); /* * Register the platform object for the OS using a supplier that lazily initializes it at * run time. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJavaEvents.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJavaEvents.java index d62c88d9468e..b7be9929e6e1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJavaEvents.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJavaEvents.java @@ -39,7 +39,7 @@ public class JfrJavaEvents { @Platforms(Platform.HOSTED_ONLY.class) @SuppressWarnings("unchecked") - public static void registerEventClass(Class eventClass) { + public static synchronized void registerEventClass(Class eventClass) { EVENT_CLASSES.add(eventClass); if (jdk.jfr.Event.class.isAssignableFrom(eventClass)) { JFR_EVENT_CLASSES.add((Class) eventClass);