Skip to content

Commit

Permalink
Document and verify GC options.
Browse files Browse the repository at this point in the history
  • Loading branch information
christianhaeubl committed Jul 22, 2022
1 parent a1226b9 commit 5c4daf5
Show file tree
Hide file tree
Showing 28 changed files with 470 additions and 346 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ protected SizeParameters computeSizeParameters(SizeParameters existing) {
long optionMaxYoung = SubstrateGCOptions.MaxNewSize.getValue();
if (optionMaxYoung > 0L) {
maxYoung = WordFactory.unsigned(optionMaxYoung);
} else if (HeapParameters.Options.MaximumYoungGenerationSizePercent.hasBeenSet()) {
} else if (GenScavengeGCOptions.MaximumYoungGenerationSizePercent.hasBeenSet()) {
maxYoung = maxHeap.unsignedDivide(100).multiply(HeapParameters.getMaximumYoungGenerationSizePercent());
} else {
maxYoung = maxHeap.unsignedDivide(AbstractCollectionPolicy.NEW_RATIO + 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@
*/
package com.oracle.svm.core.genscavenge;

import static com.oracle.svm.core.genscavenge.BasicCollectionPolicies.Options.AllocationBeforePhysicalMemorySize;
import static com.oracle.svm.core.genscavenge.BasicCollectionPolicies.Options.PercentTimeInIncrementalCollection;
import static com.oracle.svm.core.genscavenge.CollectionPolicy.shouldCollectYoungGenSeparately;

import org.graalvm.compiler.options.Option;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.UnsignedWord;
Expand All @@ -38,21 +35,11 @@
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.option.HostedOptionKey;
import com.oracle.svm.core.option.RuntimeOptionKey;
import com.oracle.svm.core.util.TimeUtils;
import com.oracle.svm.core.util.VMError;

/** Basic/legacy garbage collection policies. */
final class BasicCollectionPolicies {
public static class Options {
@Option(help = "Percentage of total collection time that should be spent on young generation collections.")//
public static final RuntimeOptionKey<Integer> PercentTimeInIncrementalCollection = new RuntimeOptionKey<>(50);

@Option(help = "Bytes that can be allocated before (re-)querying the physical memory size") //
public static final HostedOptionKey<Long> AllocationBeforePhysicalMemorySize = new HostedOptionKey<>(1L * 1024L * 1024L);
}

@Platforms(Platform.HOSTED_ONLY.class)
static int getMaxSurvivorSpaces(Integer userValue) {
assert userValue == null || userValue >= 0;
Expand Down Expand Up @@ -87,7 +74,7 @@ public void ensureSizeParametersInitialized() {
@Override
public void updateSizeParameters() {
// Sample the physical memory size, before the first GC but after some allocation.
UnsignedWord allocationBeforeUpdate = WordFactory.unsigned(AllocationBeforePhysicalMemorySize.getValue());
UnsignedWord allocationBeforeUpdate = WordFactory.unsigned(GenScavengeGCOptions.AllocationBeforePhysicalMemorySize.getValue());
if (GCImpl.getGCImpl().getCollectionEpoch().equal(WordFactory.zero()) &&
HeapImpl.getHeapImpl().getAccounting().getYoungUsedBytes().aboveOrEqual(allocationBeforeUpdate)) {
PhysicalMemory.tryInitialize();
Expand Down Expand Up @@ -252,7 +239,7 @@ private UnsignedWord estimateUsedHeapAtNextIncrementalCollection() {
}

private static boolean enoughTimeSpentOnIncrementalGCs() {
int incrementalWeight = PercentTimeInIncrementalCollection.getValue();
int incrementalWeight = SerialGCOptions.PercentTimeInIncrementalCollection.getValue();
assert incrementalWeight >= 0 && incrementalWeight <= 100 : "BySpaceAndTimePercentTimeInIncrementalCollection should be in the range [0..100].";

GCAccounting accounting = GCImpl.getGCImpl().getAccounting();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,25 @@
*/
package com.oracle.svm.core.genscavenge;

import org.graalvm.compiler.options.Option;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.UnsignedWord;

import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.heap.GCCause;
import com.oracle.svm.core.heap.PhysicalMemory;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.util.UserError;

/** The interface for a garbage collection policy. All sizes are in bytes. */
public interface CollectionPolicy {
final class Options {
@Option(help = "The garbage collection policy, either Adaptive (default) or BySpaceAndTime.")//
public static final HostedOptionKey<String> InitialCollectionPolicy = new HostedOptionKey<>("Adaptive");
}

@Platforms(Platform.HOSTED_ONLY.class)
static String getInitialPolicyName() {
if (SubstrateOptions.UseEpsilonGC.getValue()) {
return "NeverCollect";
} else if (!SubstrateOptions.useRememberedSet()) {
return "OnlyCompletely";
}
String name = Options.InitialCollectionPolicy.getValue();
String name = SerialGCOptions.InitialCollectionPolicy.getValue();
String legacyPrefix = "com.oracle.svm.core.genscavenge.CollectionPolicy$";
if (name.startsWith(legacyPrefix)) {
return name.substring(legacyPrefix.length());
Expand Down Expand Up @@ -87,7 +80,7 @@ static int getMaxSurvivorSpaces(Integer userValue) {
}

static boolean shouldCollectYoungGenSeparately(boolean defaultValue) {
Boolean optionValue = HeapParameters.Options.CollectYoungGenerationSeparately.getValue();
Boolean optionValue = SerialGCOptions.CollectYoungGenerationSeparately.getValue();
return (optionValue != null) ? optionValue : defaultValue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ void beforeCollection(boolean completeCollection) {
oldChunkBytesBefore = oldSpace.getChunkBytes();
/* Objects are allocated in the young generation. */
allocatedChunkBytes = allocatedChunkBytes.add(youngGen.getEden().getChunkBytes());
if (HeapOptions.PrintGCSummary.getValue()) {
if (SerialGCOptions.PrintGCSummary.getValue()) {
UnsignedWord edenObjectBytesBefore = youngGen.getEden().computeObjectBytes();
youngObjectBytesBefore = edenObjectBytesBefore.add(youngGen.computeSurvivorObjectBytes());
oldObjectBytesBefore = oldSpace.computeObjectBytes();
Expand Down Expand Up @@ -197,7 +197,7 @@ private void afterCollectionCommon() {
UnsignedWord afterChunkBytes = oldChunkBytesAfter.add(youngChunkBytesAfter);
UnsignedWord collectedChunkBytes = beforeChunkBytes.subtract(afterChunkBytes);
collectedTotalChunkBytes = collectedTotalChunkBytes.add(collectedChunkBytes);
if (HeapOptions.PrintGCSummary.getValue()) {
if (SerialGCOptions.PrintGCSummary.getValue()) {
UnsignedWord youngObjectBytesAfter = youngGen.computeObjectBytes();
UnsignedWord oldObjectBytesAfter = oldSpace.computeObjectBytes();
UnsignedWord beforeObjectBytes = youngObjectBytesBefore.add(oldObjectBytesBefore);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,29 +357,29 @@ public static UnsignedWord getChunkBytes() {
private void printGCBefore(String cause) {
Log verboseGCLog = Log.log();
HeapImpl heap = HeapImpl.getHeapImpl();
sizeBefore = ((SubstrateGCOptions.PrintGC.getValue() || HeapOptions.PrintHeapShape.getValue()) ? getChunkBytes() : WordFactory.zero());
sizeBefore = ((SubstrateGCOptions.PrintGC.getValue() || SerialGCOptions.PrintHeapShape.getValue()) ? getChunkBytes() : WordFactory.zero());
if (SubstrateGCOptions.VerboseGC.getValue() && getCollectionEpoch().equal(1)) {
verboseGCLog.string("[Heap policy parameters: ").newline();
verboseGCLog.string(" YoungGenerationSize: ").unsigned(getPolicy().getMaximumYoungGenerationSize()).newline();
verboseGCLog.string(" MaximumHeapSize: ").unsigned(getPolicy().getMaximumHeapSize()).newline();
verboseGCLog.string(" MinimumHeapSize: ").unsigned(getPolicy().getMinimumHeapSize()).newline();
verboseGCLog.string(" AlignedChunkSize: ").unsigned(HeapParameters.getAlignedHeapChunkSize()).newline();
verboseGCLog.string(" LargeArrayThreshold: ").unsigned(HeapParameters.getLargeArrayThreshold()).string("]").newline();
if (HeapOptions.PrintHeapShape.getValue()) {
if (SerialGCOptions.PrintHeapShape.getValue()) {
HeapImpl.getHeapImpl().logImageHeapPartitionBoundaries(verboseGCLog);
}
}
if (SubstrateGCOptions.VerboseGC.getValue()) {
verboseGCLog.string("[");
verboseGCLog.string("[");
long startTime = System.nanoTime();
if (HeapOptions.PrintGCTimeStamps.getValue()) {
if (SerialGCOptions.PrintGCTimeStamps.getValue()) {
verboseGCLog.unsigned(TimeUtils.roundNanosToMillis(Timer.getTimeSinceFirstAllocation(startTime))).string(" msec: ");
} else {
verboseGCLog.unsigned(startTime);
}
verboseGCLog.string(" GC:").string(" before").string(" epoch: ").unsigned(getCollectionEpoch()).string(" cause: ").string(cause);
if (HeapOptions.PrintHeapShape.getValue()) {
if (SerialGCOptions.PrintHeapShape.getValue()) {
heap.report(verboseGCLog);
}
verboseGCLog.string("]").newline();
Expand All @@ -394,7 +394,7 @@ private void printGCAfter(String cause) {
Log printGCLog = Log.log();
UnsignedWord sizeAfter = getChunkBytes();
printGCLog.string("[");
if (HeapOptions.PrintGCTimeStamps.getValue()) {
if (SerialGCOptions.PrintGCTimeStamps.getValue()) {
long finishNanos = timers.collection.getClosedTime();
printGCLog.unsigned(TimeUtils.roundNanosToMillis(Timer.getTimeSinceFirstAllocation(finishNanos))).string(" msec: ");
}
Expand All @@ -409,7 +409,7 @@ private void printGCAfter(String cause) {
if (SubstrateGCOptions.VerboseGC.getValue()) {
verboseGCLog.string(" [");
long finishNanos = timers.collection.getClosedTime();
if (HeapOptions.PrintGCTimeStamps.getValue()) {
if (SerialGCOptions.PrintGCTimeStamps.getValue()) {
verboseGCLog.unsigned(TimeUtils.roundNanosToMillis(Timer.getTimeSinceFirstAllocation(finishNanos))).string(" msec: ");
} else {
verboseGCLog.unsigned(finishNanos);
Expand All @@ -418,10 +418,10 @@ private void printGCAfter(String cause) {
verboseGCLog.string(" policy: ");
verboseGCLog.string(getPolicy().getName());
verboseGCLog.string(" type: ").string(completeCollection ? "complete" : "incremental");
if (HeapOptions.PrintHeapShape.getValue()) {
if (SerialGCOptions.PrintHeapShape.getValue()) {
heap.report(verboseGCLog);
}
if (!HeapOptions.PrintGCTimes.getValue()) {
if (!SerialGCOptions.PrintGCTimes.getValue()) {
verboseGCLog.newline();
verboseGCLog.string(" collection time: ").unsigned(timers.collection.getMeasuredNanos()).string(" nanoSeconds");
} else {
Expand Down Expand Up @@ -1167,7 +1167,7 @@ static void doReferenceHandling() {
long startTime = System.nanoTime();
ReferenceHandler.processPendingReferencesInRegularThread();

if (SubstrateGCOptions.VerboseGC.getValue() && HeapOptions.PrintGCTimes.getValue()) {
if (SubstrateGCOptions.VerboseGC.getValue() && SerialGCOptions.PrintGCTimes.getValue()) {
long executionTime = System.nanoTime() - startTime;
Log.log().string("[GC epilogue reference processing and cleaners: ").signed(executionTime).string("]").newline();
}
Expand Down Expand Up @@ -1349,7 +1349,7 @@ private static <T extends Header<T>> T getLast(T chunks) {
}

private void printGCSummary() {
if (!HeapOptions.PrintGCSummary.getValue()) {
if (!SerialGCOptions.PrintGCSummary.getValue()) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. 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 com.oracle.svm.core.SubstrateOptions;
import org.graalvm.collections.EconomicMap;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionType;

import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.option.NotifyGCRuntimeOptionKey;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.option.RuntimeOptionKey;
import com.oracle.svm.core.util.InterruptImageBuilding;
import com.oracle.svm.core.util.UserError;

/** Common options that can be specified for both the serial and the epsilon GC. */
public final class GenScavengeGCOptions {
@Option(help = "Serial and epsilon GC only: the maximum heap size as percent of physical memory.", type = OptionType.User) //
public static final RuntimeOptionKey<Integer> MaximumHeapSizePercent = new NotifyGCRuntimeOptionKey<>(80, GenScavengeGCOptions::serialOrEpsilonGCOnly);

@Option(help = "Serial and epsilon GC only: the maximum size of the young generation as a percentage of the maximum heap size.", type = OptionType.User) //
public static final RuntimeOptionKey<Integer> MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, GenScavengeGCOptions::serialOrEpsilonGCOnly);

@Option(help = "Serial and epsilon GC only: the size of an aligned chunk.", type = OptionType.Expert) //
public static final HostedOptionKey<Long> AlignedHeapChunkSize = new HostedOptionKey<>(1L * 1024L * 1024L, GenScavengeGCOptions::serialOrEpsilonGCOnly) {
@Override
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Long oldValue, Long newValue) {
int multiple = 4096;
UserError.guarantee(newValue > 0 && newValue % multiple == 0, "%s value must be a multiple of %d.", getName(), multiple);
}
};

/*
* This should be a fraction of the size of an aligned chunk, else large small arrays will not
* fit in an aligned chunk.
*/
@Option(help = "Serial and epsilon GC only: the size at or above which an array will be allocated in its own unaligned chunk. 0 implies (AlignedHeapChunkSize / 8).", type = OptionType.Expert) //
public static final HostedOptionKey<Long> LargeArrayThreshold = new HostedOptionKey<>(0L, GenScavengeGCOptions::serialOrEpsilonGCOnly);

@Option(help = "Serial and epsilon GC only: fill unused memory chunks with a sentinel value.", type = OptionType.Debug) //
public static final HostedOptionKey<Boolean> ZapChunks = new HostedOptionKey<>(false, GenScavengeGCOptions::serialOrEpsilonGCOnly);

@Option(help = "Serial and epsilon GC only: before use, fill memory chunks with a sentinel value.", type = OptionType.Debug) //
public static final HostedOptionKey<Boolean> ZapProducedHeapChunks = new HostedOptionKey<>(false, GenScavengeGCOptions::serialOrEpsilonGCOnly);

@Option(help = "Serial and epsilon GC only: after use, Fill memory chunks with a sentinel value.", type = OptionType.Debug) //
public static final HostedOptionKey<Boolean> ZapConsumedHeapChunks = new HostedOptionKey<>(false, GenScavengeGCOptions::serialOrEpsilonGCOnly);

@Option(help = "Serial and epsilon GC only: bytes that can be allocated before (re-)querying the physical memory size", type = OptionType.Debug) //
public static final HostedOptionKey<Long> AllocationBeforePhysicalMemorySize = new HostedOptionKey<>(1L * 1024L * 1024L, GenScavengeGCOptions::serialOrEpsilonGCOnly);

@Option(help = "Serial and epsilon GC only: number of bytes at the beginning of each heap chunk that are not used for payload data, i.e., can be freely used as metadata by the heap chunk provider.", type = OptionType.Debug) //
public static final HostedOptionKey<Integer> HeapChunkHeaderPadding = new HostedOptionKey<>(0, GenScavengeGCOptions::serialOrEpsilonGCOnly);

private GenScavengeGCOptions() {
}

private static void serialOrEpsilonGCOnly(OptionKey<?> optionKey) {
if (!SubstrateOptions.UseSerialGC.getValue() && !SubstrateOptions.UseEpsilonGC.getValue()) {
throw new InterruptImageBuilding("The option " + optionKey.getName() + " is garbage collector specific and cannot be specified if the " +
Heap.getHeap().getGC().getName() + " is used at runtime.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
*/
package com.oracle.svm.core.genscavenge;

import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.word.Word;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
Expand All @@ -37,7 +36,6 @@
import com.oracle.svm.core.heap.ReferenceAccess;
import com.oracle.svm.core.hub.LayoutEncoding;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.option.HostedOptionKey;

/**
* This visitor is handed <em>Pointers to Object references</em> and if necessary it promotes the
Expand All @@ -53,7 +51,7 @@ final class GreyToBlackObjRefVisitor implements ObjectReferenceVisitor {

@Platforms(Platform.HOSTED_ONLY.class)
GreyToBlackObjRefVisitor() {
if (Options.GreyToBlackObjRefDemographics.getValue()) {
if (SerialGCOptions.GreyToBlackObjRefDemographics.getValue()) {
counters = new RealCounters();
} else {
counters = new NoopCounters();
Expand Down Expand Up @@ -125,11 +123,6 @@ public Counters openCounters() {
return counters.open();
}

public static class Options {
@Option(help = "Develop demographics of the object references visited.")//
public static final HostedOptionKey<Boolean> GreyToBlackObjRefDemographics = new HostedOptionKey<>(false);
}

public interface Counters extends AutoCloseable {

Counters open();
Expand Down
Loading

0 comments on commit 5c4daf5

Please sign in to comment.