Skip to content

Commit d0953b0

Browse files
committed
Address review comments.
1 parent 6dc5ec2 commit d0953b0

File tree

11 files changed

+88
-106
lines changed

11 files changed

+88
-106
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.svm.core.heap.ReferenceAccess;
3737
import com.oracle.svm.core.jdk.UninterruptibleUtils;
3838
import com.oracle.svm.core.option.RuntimeOptionValues;
39+
import com.oracle.svm.core.thread.VMOperation;
3940
import com.oracle.svm.core.util.UnsignedUtils;
4041
import com.oracle.svm.core.util.VMError;
4142

@@ -48,18 +49,19 @@ abstract class AbstractCollectionPolicy implements CollectionPolicy {
4849
* Don't change these values individually without carefully going over their occurrences in
4950
* HotSpot source code, there are dependencies between them that are not handled in our code.
5051
*/
51-
static final int INITIAL_SURVIVOR_RATIO = 8;
52-
static final int MIN_SURVIVOR_RATIO = 3;
52+
protected static final int INITIAL_SURVIVOR_RATIO = 8;
53+
protected static final int MIN_SURVIVOR_RATIO = 3;
54+
protected static final int DEFAULT_TIME_WEIGHT = 25; // -XX:AdaptiveTimeWeight
5355

5456
/* Constants to compute defaults for values which can be set through existing options. */
5557
/** HotSpot: -XX:MaxHeapSize default without ergonomics. */
56-
static final UnsignedWord SMALL_HEAP_SIZE = WordFactory.unsigned(96 * 1024 * 1024);
57-
static final int NEW_RATIO = 2; // HotSpot: -XX:NewRatio
58-
static final int LARGE_MEMORY_MAX_HEAP_PERCENT = 25; // -XX:MaxRAMPercentage
59-
static final int SMALL_MEMORY_MAX_HEAP_PERCENT = 50; // -XX:MinRAMPercentage
60-
static final double INITIAL_HEAP_MEMORY_PERCENT = 1.5625; // -XX:InitialRAMPercentage
58+
protected static final UnsignedWord SMALL_HEAP_SIZE = WordFactory.unsigned(96 * 1024 * 1024);
59+
protected static final int NEW_RATIO = 2; // HotSpot: -XX:NewRatio
60+
protected static final int LARGE_MEMORY_MAX_HEAP_PERCENT = 25; // -XX:MaxRAMPercentage
61+
protected static final int SMALL_MEMORY_MAX_HEAP_PERCENT = 50; // -XX:MinRAMPercentage
62+
protected static final double INITIAL_HEAP_MEMORY_PERCENT = 1.5625; // -XX:InitialRAMPercentage
6163

62-
protected final AdaptiveWeightedAverage avgYoungGenAlignedChunkFraction = new AdaptiveWeightedAverage(AdaptiveCollectionPolicy.ADAPTIVE_TIME_WEIGHT);
64+
protected final AdaptiveWeightedAverage avgYoungGenAlignedChunkFraction = new AdaptiveWeightedAverage(DEFAULT_TIME_WEIGHT);
6365

6466
protected UnsignedWord survivorSize;
6567
protected UnsignedWord edenSize;
@@ -165,7 +167,8 @@ private void updateSizeParametersLocked(SizeParameters params, SizeParameters pr
165167
*/
166168
survivorSize = UnsignedUtils.min(survivorSize, params.maxSurvivorSize());
167169
edenSize = UnsignedUtils.min(edenSize, maxEdenSize());
168-
oldSize = UnsignedUtils.min(oldSize, sizes.maxOldSize());
170+
oldSize = UnsignedUtils.min(oldSize, params.maxOldSize());
171+
promoSize = UnsignedUtils.min(promoSize, params.maxOldSize());
169172
}
170173

171174
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@@ -187,18 +190,21 @@ public UnsignedWord getMaximumYoungGenerationSize() {
187190

188191
@Override
189192
public UnsignedWord getCurrentHeapCapacity() {
193+
assert VMOperation.isGCInProgress() : "use only during GC";
190194
guaranteeSizeParametersInitialized();
191195
return edenSize.add(survivorSize.multiply(2)).add(oldSize);
192196
}
193197

194198
@Override
195199
public UnsignedWord getSurvivorSpacesCapacity() {
200+
assert VMOperation.isGCInProgress() : "use only during GC";
196201
guaranteeSizeParametersInitialized();
197202
return survivorSize;
198203
}
199204

200205
@Override
201206
public UnsignedWord getMaximumFreeAlignedChunksSize() {
207+
assert VMOperation.isGCInProgress() : "use only during GC";
202208
guaranteeSizeParametersInitialized();
203209
/*
204210
* Keep chunks ready for allocations in eden and for the survivor to-spaces during young
@@ -207,12 +213,13 @@ public UnsignedWord getMaximumFreeAlignedChunksSize() {
207213
* getCurrentHeapCapacity() to have chunks ready during full GCs as well.
208214
*/
209215
UnsignedWord total = edenSize.add(survivorSize);
210-
float alignedFraction = Math.min(1, Math.max(0, avgYoungGenAlignedChunkFraction.getAverage()));
216+
double alignedFraction = Math.min(1, Math.max(0, avgYoungGenAlignedChunkFraction.getAverage()));
211217
return UnsignedUtils.fromDouble(UnsignedUtils.toDouble(total) * alignedFraction);
212218
}
213219

214220
@Override
215221
public int getTenuringAge() {
222+
assert VMOperation.isGCInProgress() : "use only during GC";
216223
return tenuringThreshold;
217224
}
218225

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
import com.oracle.svm.core.util.UnsignedUtils;
3434

3535
/**
36-
* A port of HotSpot's ParallelGC adaptive size policy for throughput and footprint, but without the
37-
* pause time goals. The relevant methods in this class have been adapted from classes
38-
* {@code PSAdaptiveSizePolicy} and its base class {@code AdaptiveSizePolicy}. Method and variable
39-
* names have been kept mostly the same for comparability.
36+
* A garbage collection policy that balances throughput and memory footprint.
37+
*
38+
* Much of this is based on HotSpot's ParallelGC adaptive size policy, but without the pause time
39+
* goals. Many methods in this class have been adapted from classes {@code PSAdaptiveSizePolicy} and
40+
* its base class {@code AdaptiveSizePolicy}. Method and variable names have been kept mostly the
41+
* same for comparability.
4042
*/
4143
final class AdaptiveCollectionPolicy extends AbstractCollectionPolicy {
4244

@@ -47,40 +49,40 @@ final class AdaptiveCollectionPolicy extends AbstractCollectionPolicy {
4749
* Don't change these values individually without carefully going over their occurrences in
4850
* HotSpot source code, there are dependencies between them that are not handled in our code.
4951
*/
50-
static final int ADAPTIVE_SIZE_POLICY_READY_THRESHOLD = 5;
51-
static final int ADAPTIVE_SIZE_DECREMENT_SCALE_FACTOR = 4;
52-
static final int ADAPTIVE_SIZE_POLICY_WEIGHT = 10;
53-
static final int ADAPTIVE_TIME_WEIGHT = 25;
54-
static final boolean USE_ADAPTIVE_SIZE_POLICY_WITH_SYSTEM_GC = false;
55-
static final boolean USE_ADAPTIVE_SIZE_DECAY_MAJOR_GC_COST = true;
56-
static final double ADAPTIVE_SIZE_MAJOR_GC_DECAY_TIME_SCALE = 10;
57-
static final boolean USE_ADAPTIVE_SIZE_POLICY_FOOTPRINT_GOAL = true;
58-
static final int THRESHOLD_TOLERANCE = 10;
59-
static final int SURVIVOR_PADDING = 3;
60-
static final int INITIAL_TENURING_THRESHOLD = 7;
61-
static final int PROMOTED_PADDING = 3;
62-
static final int TENURED_GENERATION_SIZE_SUPPLEMENT_DECAY = 2;
63-
static final int YOUNG_GENERATION_SIZE_SUPPLEMENT_DECAY = 8;
64-
static final int PAUSE_PADDING = 1;
52+
private static final int ADAPTIVE_TIME_WEIGHT = DEFAULT_TIME_WEIGHT;
53+
private static final int ADAPTIVE_SIZE_POLICY_READY_THRESHOLD = 5;
54+
private static final int ADAPTIVE_SIZE_DECREMENT_SCALE_FACTOR = 4;
55+
private static final int ADAPTIVE_SIZE_POLICY_WEIGHT = 10;
56+
private static final boolean USE_ADAPTIVE_SIZE_POLICY_WITH_SYSTEM_GC = false;
57+
private static final boolean USE_ADAPTIVE_SIZE_DECAY_MAJOR_GC_COST = true;
58+
private static final double ADAPTIVE_SIZE_MAJOR_GC_DECAY_TIME_SCALE = 10;
59+
private static final boolean USE_ADAPTIVE_SIZE_POLICY_FOOTPRINT_GOAL = true;
60+
private static final int THRESHOLD_TOLERANCE = 10;
61+
private static final int SURVIVOR_PADDING = 3;
62+
private static final int INITIAL_TENURING_THRESHOLD = 7;
63+
private static final int PROMOTED_PADDING = 3;
64+
private static final int TENURED_GENERATION_SIZE_SUPPLEMENT_DECAY = 2;
65+
private static final int YOUNG_GENERATION_SIZE_SUPPLEMENT_DECAY = 8;
66+
private static final int PAUSE_PADDING = 1;
6567
/**
6668
* Ratio of mutator wall-clock time to GC wall-clock time. HotSpot's default is 99, i.e.
6769
* spending 1% of time in GC. We set it to 19, i.e. 5%, to prefer a small footprint.
6870
*/
69-
static final int GC_TIME_RATIO = 19;
71+
private static final int GC_TIME_RATIO = 19;
7072
/**
7173
* Maximum size increment step percentages. We reduce them from HotSpot's default of 20 to avoid
7274
* growing the heap too eagerly, and to enable {@linkplain #ADAPTIVE_SIZE_USE_COST_ESTIMATORS
7375
* cost estimators} to resize the heap in smaller steps which might yield improved throughput
7476
* when larger steps do not.
7577
*/
76-
static final int YOUNG_GENERATION_SIZE_INCREMENT = 10;
77-
static final int TENURED_GENERATION_SIZE_INCREMENT = 10;
78+
private static final int YOUNG_GENERATION_SIZE_INCREMENT = 10;
79+
private static final int TENURED_GENERATION_SIZE_INCREMENT = 10;
7880
/*
7981
* Supplements to accelerate the expansion of the heap at startup. We do not use them in favor
8082
* of a small footprint.
8183
*/
82-
static final int YOUNG_GENERATION_SIZE_SUPPLEMENT = 0; // HotSpot default: 80
83-
static final int TENURED_GENERATION_SIZE_SUPPLEMENT = 0; // HotSpot default: 80
84+
private static final int YOUNG_GENERATION_SIZE_SUPPLEMENT = 0; // HotSpot default: 80
85+
private static final int TENURED_GENERATION_SIZE_SUPPLEMENT = 0; // HotSpot default: 80
8486
/**
8587
* Use least square fitting to estimate if increasing heap sizes will significantly improve
8688
* throughput. This is intended to limit memory usage once throughput cannot be increased much
@@ -89,18 +91,18 @@ final class AdaptiveCollectionPolicy extends AbstractCollectionPolicy {
8991
* discounting of old data points, unlike HotSpot's AdaptiveSizeThroughPutPolicy option
9092
* (disabled by default) which uses linear least-square fitting without discounting.
9193
*/
92-
static final boolean ADAPTIVE_SIZE_USE_COST_ESTIMATORS = true;
93-
static final int ADAPTIVE_SIZE_POLICY_INITIALIZING_STEPS = ADAPTIVE_SIZE_POLICY_READY_THRESHOLD;
94+
private static final boolean ADAPTIVE_SIZE_USE_COST_ESTIMATORS = true;
95+
private static final int ADAPTIVE_SIZE_POLICY_INITIALIZING_STEPS = ADAPTIVE_SIZE_POLICY_READY_THRESHOLD;
9496
/** The minimum increase in throughput in percent for expanding a space by 1% of its size. */
95-
static final double ADAPTIVE_SIZE_ESTIMATOR_MIN_SIZE_THROUGHPUT_TRADEOFF = 0.8;
97+
private static final double ADAPTIVE_SIZE_ESTIMATOR_MIN_SIZE_THROUGHPUT_TRADEOFF = 0.8;
9698
/** The effective number of most recent data points used by estimator (exponential decay). */
97-
static final int ADAPTIVE_SIZE_COST_ESTIMATORS_HISTORY_LENGTH = ADAPTIVE_TIME_WEIGHT;
99+
private static final int ADAPTIVE_SIZE_COST_ESTIMATORS_HISTORY_LENGTH = ADAPTIVE_TIME_WEIGHT;
98100
/** Threshold for triggering a complete collection after repeated minor collections. */
99-
static final int CONSECUTIVE_MINOR_TO_MAJOR_COLLECTION_PAUSE_TIME_RATIO = 2;
101+
private static final int CONSECUTIVE_MINOR_TO_MAJOR_COLLECTION_PAUSE_TIME_RATIO = 2;
100102

101103
/* Constants derived from other constants. */
102-
static final double THROUGHPUT_GOAL = 1.0 - 1.0 / (1.0 + GC_TIME_RATIO);
103-
static final double THRESHOLD_TOLERANCE_PERCENT = 1.0 + THRESHOLD_TOLERANCE / 100.0;
104+
private static final double THROUGHPUT_GOAL = 1.0 - 1.0 / (1.0 + GC_TIME_RATIO);
105+
private static final double THRESHOLD_TOLERANCE_PERCENT = 1.0 + THRESHOLD_TOLERANCE / 100.0;
104106

105107
private final Timer minorTimer = new Timer("minor/between minor");
106108
private final AdaptiveWeightedAverage avgMinorGcCost = new AdaptiveWeightedAverage(ADAPTIVE_TIME_WEIGHT);
@@ -381,7 +383,7 @@ public void onCollectionBegin(boolean completeCollection) { // {major,minor}_col
381383
UnsignedWord youngChunkBytes = GCImpl.getGCImpl().getAccounting().getYoungChunkBytesBefore();
382384
if (youngChunkBytes.notEqual(0)) {
383385
UnsignedWord youngAlignedChunkBytes = HeapImpl.getHeapImpl().getYoungGeneration().getAlignedChunkBytes();
384-
avgYoungGenAlignedChunkFraction.sample(UnsignedUtils.toFloat(youngAlignedChunkBytes) / UnsignedUtils.toFloat(youngChunkBytes));
386+
avgYoungGenAlignedChunkFraction.sample(UnsignedUtils.toDouble(youngAlignedChunkBytes) / UnsignedUtils.toDouble(youngChunkBytes));
385387
}
386388

387389
timer.reset();
@@ -534,13 +536,13 @@ private static void updateCollectionEndAverages(AdaptiveWeightedAverage costAver
534536
double cost = 0;
535537
double mutatorInSeconds = TimeUtils.nanosToSecondsDouble(mutatorNanos);
536538
double pauseInSeconds = TimeUtils.nanosToSecondsDouble(pauseNanos);
537-
pauseAverage.sample((float) pauseInSeconds);
539+
pauseAverage.sample(pauseInSeconds);
538540
if (mutatorInSeconds > 0 && pauseInSeconds > 0) {
539541
double intervalInSeconds = mutatorInSeconds + pauseInSeconds;
540542
cost = pauseInSeconds / intervalInSeconds;
541-
costAverage.sample((float) cost);
543+
costAverage.sample(cost);
542544
if (intervalSeconds != null) {
543-
intervalSeconds.sample((float) intervalInSeconds);
545+
intervalSeconds.sample(intervalInSeconds);
544546
}
545547
}
546548
costEstimator.sample(UnsignedUtils.toDouble(sizeBytes), cost);

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveWeightedAverage.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import com.oracle.svm.core.util.UnsignedUtils;
3030

3131
/**
32-
* A weighted average maintains a running, weighted average of some float value.
32+
* A weighted average maintains a running, weighted average of some floating-point value.
3333
*
3434
* The average is adaptive in that we smooth it for the initial samples; we don't use the weight
3535
* until we have enough samples for it to be meaningful.
@@ -41,24 +41,24 @@ class AdaptiveWeightedAverage {
4141

4242
private final int weight;
4343

44-
private float average;
44+
private double average;
4545
private long sampleCount;
4646
private boolean isOld;
4747

4848
AdaptiveWeightedAverage(int weight) {
49-
this(weight, 0.0f);
49+
this(weight, 0);
5050
}
5151

52-
AdaptiveWeightedAverage(int weight, float avg) {
52+
AdaptiveWeightedAverage(int weight, double avg) {
5353
this.weight = weight;
5454
this.average = avg;
5555
}
5656

57-
public float getAverage() {
57+
public double getAverage() {
5858
return average;
5959
}
6060

61-
public void sample(float value) {
61+
public void sample(double value) {
6262
sampleCount++;
6363
if (!isOld && sampleCount > OLD_THRESHOLD) {
6464
isOld = true;
@@ -67,10 +67,10 @@ public void sample(float value) {
6767
}
6868

6969
public final void sample(UnsignedWord value) {
70-
sample(UnsignedUtils.toFloat(value));
70+
sample(UnsignedUtils.toDouble(value));
7171
}
7272

73-
protected float computeAdaptiveAverage(float sample, float avg) {
73+
protected double computeAdaptiveAverage(double sample, double avg) {
7474
/*
7575
* We smoothen the samples by not using weight directly until we've had enough data to make
7676
* it meaningful. We'd like the first weight used to be 1, the second to be 1/2, etc until
@@ -84,9 +84,9 @@ protected float computeAdaptiveAverage(float sample, float avg) {
8484
return expAvg(avg, sample, adaptiveWeight);
8585
}
8686

87-
private static float expAvg(float avg, float sample, long adaptiveWeight) {
87+
private static double expAvg(double avg, double sample, long adaptiveWeight) {
8888
assert adaptiveWeight <= 100 : "weight must be a percentage";
89-
return (100.0f - adaptiveWeight) * avg / 100.0f + adaptiveWeight * sample / 100.0f;
89+
return (100.0 - adaptiveWeight) * avg / 100.0 + adaptiveWeight * sample / 100.0;
9090
}
9191
}
9292

@@ -100,8 +100,8 @@ class AdaptivePaddedAverage extends AdaptiveWeightedAverage {
100100
private final int padding;
101101
private final boolean noZeroDeviations;
102102

103-
private float paddedAverage;
104-
private float deviation;
103+
private double paddedAverage;
104+
private double deviation;
105105

106106
AdaptivePaddedAverage(int weight, int padding) {
107107
this(weight, padding, false);
@@ -119,20 +119,20 @@ class AdaptivePaddedAverage extends AdaptiveWeightedAverage {
119119
}
120120

121121
@Override
122-
public void sample(float value) {
122+
public void sample(double value) {
123123
super.sample(value);
124-
float average = super.getAverage();
124+
double average = super.getAverage();
125125
if (value != 0 || !noZeroDeviations) {
126126
deviation = computeAdaptiveAverage(Math.abs(value - average), deviation);
127127
}
128128
paddedAverage = average + padding * deviation;
129129
}
130130

131-
public float getPaddedAverage() {
131+
public double getPaddedAverage() {
132132
return paddedAverage;
133133
}
134134

135-
public float getDeviation() {
135+
public double getDeviation() {
136136
return deviation;
137137
}
138138
}

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,7 @@
4040
import com.oracle.svm.core.util.TimeUtils;
4141
import com.oracle.svm.core.util.VMError;
4242

43-
/**
44-
* Garbage collection policies. These are referenced by fully-qualified class names and should not
45-
* be renamed or moved.
46-
*/
43+
/** Basic/legacy garbage collection policies. */
4744
final class BasicCollectionPolicies {
4845
public static class Options {
4946
@Option(help = "Percentage of total collection time that should be spent on young generation collections.")//

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.graalvm.compiler.options.Option;
2828
import org.graalvm.nativeimage.Platform;
2929
import org.graalvm.nativeimage.Platforms;
30-
import org.graalvm.nativeimage.hosted.Feature;
3130
import org.graalvm.word.UnsignedWord;
3231

3332
import com.oracle.svm.core.SubstrateOptions;
@@ -39,12 +38,12 @@
3938
/** The interface for a garbage collection policy. All sizes are in bytes. */
4039
public interface CollectionPolicy {
4140
final class Options {
42-
@Option(help = "The garbage collection policy, one of Adaptive, BySpaceAndTime, OnlyCompletely, OnlyIncrementally, NeverCollect, or the fully-qualified name of a custom policy class.")//
43-
public static final HostedOptionKey<String> InitialCollectionPolicy = new HostedOptionKey<>(AdaptiveCollectionPolicy.class.getName());
41+
@Option(help = "The garbage collection policy, either Adaptive (default) or BySpaceAndTime.")//
42+
public static final HostedOptionKey<String> InitialCollectionPolicy = new HostedOptionKey<>("Adaptive");
4443
}
4544

4645
@Platforms(Platform.HOSTED_ONLY.class)
47-
static CollectionPolicy getInitialPolicy(Feature.FeatureAccess access) {
46+
static CollectionPolicy getInitialPolicy() {
4847
if (SubstrateOptions.UseEpsilonGC.getValue()) {
4948
return new BasicCollectionPolicies.NeverCollect();
5049
} else if (!SubstrateOptions.useRememberedSet()) {
@@ -69,18 +68,7 @@ static CollectionPolicy getInitialPolicy(Feature.FeatureAccess access) {
6968
case "NeverCollect":
7069
return new BasicCollectionPolicies.NeverCollect();
7170
}
72-
Class<?> policyClass = access.findClassByName(name);
73-
if (policyClass == null) {
74-
throw UserError.abort("Policy %s does not exist. If it is a custom policy class, it must be a fully qualified class name, which might require quotes or escaping.", name);
75-
}
76-
if (!CollectionPolicy.class.isAssignableFrom(policyClass)) {
77-
throw UserError.abort("Policy %s does not extend %s.", name, CollectionPolicy.class.getTypeName());
78-
}
79-
try {
80-
return (CollectionPolicy) policyClass.getDeclaredConstructor().newInstance();
81-
} catch (Exception ex) {
82-
throw UserError.abort(ex, "Policy %s cannot be instantiated.", name);
83-
}
71+
throw UserError.abort("Policy %s does not exist.", name);
8472
}
8573

8674
String getName();
@@ -119,8 +107,7 @@ static CollectionPolicy getInitialPolicy(Feature.FeatureAccess access) {
119107

120108
/**
121109
* The current limit for the size of the entire heap, which is less than or equal to
122-
* {@link #getMaximumHeapSize}. Outside of the policy, this limit is used only for free space
123-
* calculations.
110+
* {@link #getMaximumHeapSize}.
124111
*
125112
* NOTE: this can currently be exceeded during a collection while copying objects in the old
126113
* generation.

0 commit comments

Comments
 (0)