Use `PercentageConverter` to automatically validate the value of `--experimental_oom_more_eagerly_threshold`.
There's no need to validate it manually. Also, this makes validation happen even if we disable `RetainedHeapLimiter` in favor of `GcThrashingDetector` (the flag is used by both classes).
PiperOrigin-RevId: 520407887
Change-Id: I5a13d32b3207febc622cd55dbcc1b62a6f670d3c
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureModule.java b/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureModule.java
index b00f029..831e3ba 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureModule.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureModule.java
@@ -20,7 +20,6 @@
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.runtime.MemoryPressure.MemoryPressureStats;
import com.google.devtools.build.lib.skyframe.HighWaterMarkLimiter;
-import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.common.options.OptionsBase;
import com.google.errorprone.annotations.Keep;
@@ -47,7 +46,7 @@
}
@Override
- public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
+ public void beforeCommand(CommandEnvironment env) {
eventBus = env.getEventBus();
memoryPressureListener.setEventBus(eventBus);
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureOptions.java b/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureOptions.java
index 4e69bed..d9ce4f5 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/MemoryPressureOptions.java
@@ -13,7 +13,8 @@
// limitations under the License.
package com.google.devtools.build.lib.runtime;
-import com.google.devtools.common.options.Converters;
+import com.google.devtools.common.options.Converters.PercentageConverter;
+import com.google.devtools.common.options.Converters.RangeConverter;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionDocumentationCategory;
import com.google.devtools.common.options.OptionEffectTag;
@@ -28,6 +29,7 @@
defaultValue = "100",
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
+ converter = PercentageConverter.class,
help =
"If this flag is set to a value less than 100, Bazel will OOM if, after two full GC's, "
+ "more than this percentage of the (old gen) heap is still occupied.")
@@ -89,8 +91,8 @@
+ " threshold is exceeded.")
public int skyframeHighWaterMarkFullGcDropsPerInvocation;
- static class NonNegativeIntegerConverter extends Converters.RangeConverter {
- public NonNegativeIntegerConverter() {
+ static final class NonNegativeIntegerConverter extends RangeConverter {
+ NonNegativeIntegerConverter() {
super(0, Integer.MAX_VALUE);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java b/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java
index 69c242f..4d94f86 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java
@@ -25,10 +25,6 @@
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.concurrent.ThreadSafety;
import com.google.devtools.build.lib.runtime.MemoryPressure.MemoryPressureStats;
-import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
-import com.google.devtools.build.lib.server.FailureDetails.MemoryOptions;
-import com.google.devtools.build.lib.util.AbruptExitException;
-import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.common.options.Options;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -74,25 +70,10 @@
}
@ThreadSafety.ThreadCompatible // Can only be called on the logical main Bazel thread.
- void setOptions(MemoryPressureOptions options) throws AbruptExitException {
- if (options.oomMoreEagerlyThreshold < 0 || options.oomMoreEagerlyThreshold > 100) {
- throw createExitException(
- "--experimental_oom_more_eagerly_threshold must be a percent between 0 and 100 but was "
- + options.oomMoreEagerlyThreshold,
- MemoryOptions.Code.EXPERIMENTAL_OOM_MORE_EAGERLY_THRESHOLD_INVALID_VALUE);
- }
+ void setOptions(MemoryPressureOptions options) {
this.options = options;
}
- private static AbruptExitException createExitException(String message, MemoryOptions.Code code) {
- return new AbruptExitException(
- DetailedExitCode.of(
- FailureDetail.newBuilder()
- .setMessage(message)
- .setMemoryOptions(MemoryOptions.newBuilder().setCode(code))
- .build()));
- }
-
// Can be called concurrently, handles concurrent calls with #setThreshold gracefully.
@ThreadSafety.ThreadSafe
public void handle(MemoryPressureEvent event) {
diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto
index 21bf208..ec3c67e 100644
--- a/src/main/protobuf/failure_details.proto
+++ b/src/main/protobuf/failure_details.proto
@@ -630,8 +630,9 @@
message MemoryOptions {
enum Code {
MEMORY_OPTIONS_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
- EXPERIMENTAL_OOM_MORE_EAGERLY_THRESHOLD_INVALID_VALUE = 1
- [(metadata) = { exit_code: 2 }];
+ // Deprecated: validation is now implemented by the option converter.
+ DEPRECATED_EXPERIMENTAL_OOM_MORE_EAGERLY_THRESHOLD_INVALID_VALUE = 1
+ [(metadata) = { exit_code: 2 }, deprecated = true];
// Deprecated: no tenured collectors found is now a crash on startup.
DEPRECATED_EXPERIMENTAL_OOM_MORE_EAGERLY_NO_TENURED_COLLECTORS_FOUND = 2
[(metadata) = { exit_code: 2 }, deprecated = true];
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiterTest.java b/src/test/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiterTest.java
index 9ba856d..06d0cb2 100644
--- a/src/test/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiterTest.java
+++ b/src/test/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiterTest.java
@@ -17,7 +17,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
-import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -27,11 +26,8 @@
import com.google.devtools.build.lib.bugreport.BugReporter;
import com.google.devtools.build.lib.bugreport.Crash;
import com.google.devtools.build.lib.runtime.MemoryPressure.MemoryPressureStats;
-import com.google.devtools.build.lib.server.FailureDetails.MemoryOptions.Code;
import com.google.devtools.build.lib.testutil.ManualClock;
-import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.common.options.Options;
-import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import java.lang.ref.WeakReference;
import java.time.Duration;
@@ -64,7 +60,7 @@
}
@Test
- public void underThreshold_noOom() throws Exception {
+ public void underThreshold_noOom() {
options.oomMoreEagerlyThreshold = 99;
underTest.setOptions(options);
@@ -76,7 +72,7 @@
}
@Test
- public void overThreshold_oom() throws Exception {
+ public void overThreshold_oom() {
options.oomMoreEagerlyThreshold = 90;
underTest.setOptions(options);
@@ -95,7 +91,7 @@
}
@Test
- public void inactiveAfterOom() throws Exception {
+ public void inactiveAfterOom() {
options.oomMoreEagerlyThreshold = 90;
options.minTimeBetweenTriggeredGc = Duration.ZERO;
underTest.setOptions(options);
@@ -116,7 +112,7 @@
}
@Test
- public void externalGcNoTrigger() throws Exception {
+ public void externalGcNoTrigger() {
options.oomMoreEagerlyThreshold = 90;
underTest.setOptions(options);
@@ -131,7 +127,7 @@
}
@Test
- public void triggerReset() throws Exception {
+ public void triggerReset() {
options.oomMoreEagerlyThreshold = 90;
underTest.setOptions(options);
@@ -146,7 +142,7 @@
}
@Test
- public void triggerRaceWithOtherGc() throws Exception {
+ public void triggerRaceWithOtherGc() {
options.oomMoreEagerlyThreshold = 90;
underTest.setOptions(options);
@@ -160,7 +156,7 @@
}
@Test
- public void minTimeBetweenGc_lessThan_noGc() throws Exception {
+ public void minTimeBetweenGc_lessThan_noGc() {
options.oomMoreEagerlyThreshold = 90;
options.minTimeBetweenTriggeredGc = Duration.ofMinutes(1);
underTest.setOptions(options);
@@ -182,7 +178,7 @@
}
@Test
- public void minTimeBetweenGc_greaterThan_gc() throws Exception {
+ public void minTimeBetweenGc_greaterThan_gc() {
options.oomMoreEagerlyThreshold = 90;
options.minTimeBetweenTriggeredGc = Duration.ofMinutes(1);
underTest.setOptions(options);
@@ -204,7 +200,7 @@
}
@Test
- public void gcLockerDefersManualGc_timeoutCancelled() throws Exception {
+ public void gcLockerDefersManualGc_timeoutCancelled() {
options.oomMoreEagerlyThreshold = 90;
options.minTimeBetweenTriggeredGc = Duration.ofMinutes(1);
underTest.setOptions(options);
@@ -218,7 +214,7 @@
}
@Test
- public void gcLockerAfterSuccessfulManualGc_timeoutPreserved() throws Exception {
+ public void gcLockerAfterSuccessfulManualGc_timeoutPreserved() {
options.oomMoreEagerlyThreshold = 90;
options.minTimeBetweenTriggeredGc = Duration.ofMinutes(1);
underTest.setOptions(options);
@@ -233,7 +229,7 @@
}
@Test
- public void reportsMaxConsecutiveIgnored() throws Exception {
+ public void reportsMaxConsecutiveIgnored() {
options.oomMoreEagerlyThreshold = 90;
options.minTimeBetweenTriggeredGc = Duration.ofMinutes(1);
underTest.setOptions(options);
@@ -269,7 +265,7 @@
}
@Test
- public void threshold100_noGcTriggeredEvenWithNonsenseStats() throws Exception {
+ public void threshold100_noGcTriggeredEvenWithNonsenseStats() {
options.oomMoreEagerlyThreshold = 100;
underTest.setOptions(options);
WeakReference<?> ref = new WeakReference<>(new Object());
@@ -287,7 +283,7 @@
}
@Test
- public void statsReset() throws Exception {
+ public void statsReset() {
options.oomMoreEagerlyThreshold = 90;
underTest.setOptions(options);
@@ -297,15 +293,6 @@
assertStats(MemoryPressureStats.newBuilder().setManuallyTriggeredGcs(0));
}
- @Test
- public void invalidThreshold_throws(@TestParameter({"-1", "101"}) int threshold) {
- options.oomMoreEagerlyThreshold = threshold;
- AbruptExitException e =
- assertThrows(AbruptExitException.class, () -> underTest.setOptions(options));
- assertThat(e.getDetailedExitCode().getFailureDetail().getMemoryOptions().getCode())
- .isEqualTo(Code.EXPERIMENTAL_OOM_MORE_EAGERLY_THRESHOLD_INVALID_VALUE);
- }
-
private static MemoryPressureEvent percentUsedAfterManualGc(int percentUsed) {
return percentUsedAfterGc(percentUsed).setWasManualGc(true).setWasFullGc(true).build();
}