Add peak post heap size to the BEP memory metrics.
Note that you have to pass the option
--bep_publish_used_heap_size_post_build
for this metric to be populated.
It is also not set when there was no major GC during this invocation.
RELNOTES: None
PiperOrigin-RevId: 289610222
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
index 97b4c70..5d675e9 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
@@ -687,6 +687,10 @@
// --bep_publish_used_heap_size_post_build is set,
// since it forces a full GC.
int64 used_heap_size_post_build = 1;
+
+ // Size of the peak JVM heap size in bytes post GC. Note that this reports 0
+ // if there was no major GC during the build.
+ int64 peak_post_gc_heap_size = 2;
}
MemoryMetrics memory_metrics = 2;
diff --git a/src/main/java/com/google/devtools/build/lib/metrics/MetricsCollector.java b/src/main/java/com/google/devtools/build/lib/metrics/MetricsCollector.java
index e94483d..d13c5b1 100644
--- a/src/main/java/com/google/devtools/build/lib/metrics/MetricsCollector.java
+++ b/src/main/java/com/google/devtools/build/lib/metrics/MetricsCollector.java
@@ -30,6 +30,7 @@
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.time.Duration;
+import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
class MetricsCollector {
@@ -97,6 +98,11 @@
System.gc();
MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
memoryMetrics.setUsedHeapSizePostBuild(memBean.getHeapMemoryUsage().getUsed());
+ Optional<Long> peakPostGcHeapSize =
+ PostGCMemoryUseRecorder.get().getPeakPostGCHeapMemoryUsed();
+ if (peakPostGcHeapSize.isPresent()) {
+ memoryMetrics.setPeakPostGcHeapSize(peakPostGcHeapSize.get());
+ }
}
return memoryMetrics.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorder.java b/src/main/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorder.java
index 9a80081..7103749 100644
--- a/src/main/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorder.java
+++ b/src/main/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorder.java
@@ -36,6 +36,7 @@
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.util.Map;
+import java.util.Optional;
import java.util.logging.Logger;
import javax.management.Notification;
import javax.management.NotificationEmitter;
@@ -69,7 +70,7 @@
private static final Logger logger = Logger.getLogger(PostGCMemoryUseRecorder.class.getName());
// Protected by PostGCMemoryUseRecorder's lock.
- private long peakPostGCHeapMemoryUsed = 0;
+ private Optional<Long> peakPostGCHeapMemoryUsed = Optional.empty();
// Protected by PostGcMemoryUseRecorder's lock. Set to true iff a GarbageCollectionNotification
// reported that we were using no memory.
@@ -87,7 +88,7 @@
}
}
- public synchronized long getPeakPostGCHeapMemoryUsed() {
+ public synchronized Optional<Long> getPeakPostGCHeapMemoryUsed() {
return peakPostGCHeapMemoryUsed;
}
@@ -96,12 +97,16 @@
}
public synchronized void reset() {
- peakPostGCHeapMemoryUsed = 0;
+ peakPostGCHeapMemoryUsed = Optional.empty();
memoryUsageReportedZero = false;
}
private synchronized void updatePostGCHeapMemoryUsed(long used) {
- peakPostGCHeapMemoryUsed = Math.max(used, peakPostGCHeapMemoryUsed);
+ if (peakPostGCHeapMemoryUsed.isPresent()) {
+ peakPostGCHeapMemoryUsed = Optional.of(Math.max(used, peakPostGCHeapMemoryUsed.get()));
+ } else {
+ peakPostGCHeapMemoryUsed = Optional.of(used);
+ }
}
private synchronized void updateMemoryUsageReportedZero(boolean value) {
@@ -179,9 +184,13 @@
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env) {
- return print(
- StringUtilities.prettyPrintBytes(
- PostGCMemoryUseRecorder.get().getPeakPostGCHeapMemoryUsed()));
+ if (PostGCMemoryUseRecorder.get().getPeakPostGCHeapMemoryUsed().isPresent()) {
+ return print(
+ StringUtilities.prettyPrintBytes(
+ PostGCMemoryUseRecorder.get().getPeakPostGCHeapMemoryUsed().get()));
+ } else {
+ return print("unknown");
+ }
}
}
@@ -221,7 +230,7 @@
@Override
public void afterCommand() {
- if (forceGc && PostGCMemoryUseRecorder.get().getPeakPostGCHeapMemoryUsed() == 0L) {
+ if (forceGc && !PostGCMemoryUseRecorder.get().getPeakPostGCHeapMemoryUsed().isPresent()) {
System.gc();
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/metrics/BUILD b/src/test/java/com/google/devtools/build/lib/metrics/BUILD
index fd003c8..6878c15 100644
--- a/src/test/java/com/google/devtools/build/lib/metrics/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/metrics/BUILD
@@ -16,5 +16,6 @@
"//third_party:junit4",
"//third_party:mockito",
"//third_party:truth",
+ "//third_party:truth8",
],
)
diff --git a/src/test/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorderTest.java b/src/test/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorderTest.java
index c3ac5c7..7b67cf0 100644
--- a/src/test/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/metrics/PostGCMemoryUseRecorderTest.java
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.metrics;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth8.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -130,19 +131,17 @@
}
@Test
- public void peakHeapStartsAtZero() {
- PostGCMemoryUseRecorder rec =
- new PostGCMemoryUseRecorder(new ArrayList<GarbageCollectorMXBean>());
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(0L);
+ public void peakHeapStartsAbsent() {
+ PostGCMemoryUseRecorder rec = new PostGCMemoryUseRecorder(new ArrayList<>());
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEmpty();
}
@Test
- public void peakHeapZeroAfterReset() {
- PostGCMemoryUseRecorder rec =
- new PostGCMemoryUseRecorder(new ArrayList<GarbageCollectorMXBean>());
+ public void peakHeapAbsentAfterReset() {
+ PostGCMemoryUseRecorder rec = new PostGCMemoryUseRecorder(new ArrayList<>());
rec.handleNotification(createMajorGCNotification(1000L), null);
rec.reset();
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(0);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEmpty();
}
@Test
@@ -157,63 +156,58 @@
underTest.doHandleNotification(notificationWithNoGcCause, /*handback=*/ null);
- assertThat(underTest.getPeakPostGCHeapMemoryUsed()).isEqualTo(100L);
+ assertThat(underTest.getPeakPostGCHeapMemoryUsed()).hasValue(100L);
}
@Test
public void peakHeapIncreasesWhenBigger() {
- PostGCMemoryUseRecorder rec =
- new PostGCMemoryUseRecorder(new ArrayList<GarbageCollectorMXBean>());
+ PostGCMemoryUseRecorder rec = new PostGCMemoryUseRecorder(new ArrayList<>());
rec.handleNotification(createMajorGCNotification(1000L), null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(1000L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).hasValue(1000L);
rec.handleNotification(createMajorGCNotification(1001L), null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(1001L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).hasValue(1001L);
rec.handleNotification(createMajorGCNotification(2001L), null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(2001L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).hasValue(2001L);
}
@Test
public void peakHeapDoesntDecrease() {
- PostGCMemoryUseRecorder rec =
- new PostGCMemoryUseRecorder(new ArrayList<GarbageCollectorMXBean>());
+ PostGCMemoryUseRecorder rec = new PostGCMemoryUseRecorder(new ArrayList<>());
rec.handleNotification(createMajorGCNotification(1000L), null);
rec.handleNotification(createMajorGCNotification(500L), null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(1000L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).hasValue(1000L);
rec.handleNotification(createMajorGCNotification(999L), null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(1000L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).hasValue(1000L);
}
@Test
public void ignoreNonGCNotification() {
- PostGCMemoryUseRecorder rec =
- new PostGCMemoryUseRecorder(new ArrayList<GarbageCollectorMXBean>());
+ PostGCMemoryUseRecorder rec = new PostGCMemoryUseRecorder(new ArrayList<>());
rec.handleNotification(
createMockNotification(
"some other notification", "end of major GC", ImmutableMap.of("Foo", 1000L)),
null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(0L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEmpty();
}
@Test
public void ignoreNonMajorGCNotification() {
- PostGCMemoryUseRecorder rec =
- new PostGCMemoryUseRecorder(new ArrayList<GarbageCollectorMXBean>());
+ PostGCMemoryUseRecorder rec = new PostGCMemoryUseRecorder(new ArrayList<>());
rec.handleNotification(
createMockNotification(
GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION,
"end of minor GC",
ImmutableMap.of("Foo", 1000L)),
null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(0L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEmpty();
}
@Test
public void sumMemUsageInfo() {
- PostGCMemoryUseRecorder rec =
- new PostGCMemoryUseRecorder(new ArrayList<GarbageCollectorMXBean>());
+ PostGCMemoryUseRecorder rec = new PostGCMemoryUseRecorder(new ArrayList<>());
rec.handleNotification(
createMajorGCNotification(ImmutableMap.of("Foo", 111L, "Bar", 222L, "Qux", 333L)), null);
- assertThat(rec.getPeakPostGCHeapMemoryUsed()).isEqualTo(666L);
+ assertThat(rec.getPeakPostGCHeapMemoryUsed()).hasValue(666L);
}
@Test