Require explicit ExecKind in SpawnMetrics.Builder and remove SpawnMetrics.EMPTY
Previously we used `REMOTE` as the default but now we'll require setting
`ExecKind` explicitly. To make it less error prone, I've introduced a few
factory methods that set it. Also, as previously discussed, I've introduced
a new `ExecKind.OTHER` (IMHO sounds a bit better than the initial proposal
of `INTERNAL`, but I don't feel strongly, so let me know if you prefer
the latter).
We also discussed not setting `ExecKind` in `SpawnMetrics.EMPTY` (and using
something like `null`), but I found it a bit tricky to really define what
that would actually mean, now that we have `ExecKind` (e.g., should we allow
aggregating such "empty" values? if yes, should it be commutative? etc.)
But I've noticed that after the introduction of `AggregatedSpawnMetrics`,
we only use `EMPTY` in one place and it's possible to simply remove it, which
avoids the problem.
RELNOTES: None.
PiperOrigin-RevId: 314687611
diff --git a/src/main/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetrics.java b/src/main/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetrics.java
index 792d2b2..4d4ba33 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetrics.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetrics.java
@@ -43,7 +43,7 @@
private static final ImmutableMap<SpawnMetrics.ExecKind, SpawnMetrics> createEmptyMetrics() {
EnumMap<SpawnMetrics.ExecKind, SpawnMetrics> map = new EnumMap<>(SpawnMetrics.ExecKind.class);
for (SpawnMetrics.ExecKind kind : SpawnMetrics.ExecKind.values()) {
- map.put(kind, new SpawnMetrics.Builder().setExecKind(kind).build());
+ map.put(kind, SpawnMetrics.Builder.forExec(kind).build());
}
return Maps.immutableEnumMap(map);
}
@@ -93,8 +93,7 @@
public AggregatedSpawnMetrics sumAllMetrics(SpawnMetrics other) {
SpawnMetrics existing = getMetrics(other.execKind());
SpawnMetrics.Builder builder =
- new SpawnMetrics.Builder()
- .setExecKind(other.execKind())
+ SpawnMetrics.Builder.forExec(other.execKind())
.addDurations(existing)
.addDurations(other)
.addNonDurations(existing)
@@ -113,8 +112,7 @@
public AggregatedSpawnMetrics sumDurationsMaxOther(SpawnMetrics other) {
SpawnMetrics existing = getMetrics(other.execKind());
SpawnMetrics.Builder builder =
- new SpawnMetrics.Builder()
- .setExecKind(other.execKind())
+ SpawnMetrics.Builder.forExec(other.execKind())
.addDurations(existing)
.addDurations(other)
.maxNonDurations(existing)
@@ -205,8 +203,7 @@
}
private SpawnMetrics.Builder getBuilder(SpawnMetrics.ExecKind kind) {
- return builderMap.computeIfAbsent(
- kind, (SpawnMetrics.ExecKind k) -> new SpawnMetrics.Builder().setExecKind(k));
+ return builderMap.computeIfAbsent(kind, SpawnMetrics.Builder::forExec);
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java b/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java
index 703f091..f6cf871 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.actions;
import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -25,7 +26,12 @@
public static enum ExecKind {
REMOTE("Remote"),
LOCAL("Local"),
- WORKER("Worker");
+ WORKER("Worker"),
+ /**
+ * Other kinds of execution (or when it's not clear whether something happened locally or
+ * remotely).
+ */
+ OTHER("Other");
private final String name;
@@ -42,16 +48,8 @@
/** Any non important stats < than 10% will not be shown in the summary. */
private static final double STATS_SHOW_THRESHOLD = 0.10;
- /** Represents a zero cost/null statistic. */
- public static final SpawnMetrics EMPTY_REMOTE =
- new Builder().setExecKind(ExecKind.REMOTE).build();
-
public static SpawnMetrics forLocalExecution(Duration wallTime) {
- return new Builder()
- .setExecKind(ExecKind.LOCAL)
- .setTotalTime(wallTime)
- .setExecutionWallTime(wallTime)
- .build();
+ return Builder.forLocalExec().setTotalTime(wallTime).setExecutionWallTime(wallTime).build();
}
private final ExecKind execKind;
@@ -69,36 +67,6 @@
private final long inputFiles;
private final long memoryEstimateBytes;
- public SpawnMetrics(
- Duration totalTime,
- Duration parseTime,
- Duration networkTime,
- Duration fetchTime,
- Duration queueTime,
- Duration setupTime,
- Duration uploadTime,
- Duration executionWallTime,
- Duration retryTime,
- Duration processOutputsTime,
- long inputBytes,
- long inputFiles,
- long memoryEstimateBytes) {
- this.execKind = ExecKind.REMOTE;
- this.totalTime = totalTime;
- this.parseTime = parseTime;
- this.networkTime = networkTime;
- this.fetchTime = fetchTime;
- this.queueTime = queueTime;
- this.setupTime = setupTime;
- this.uploadTime = uploadTime;
- this.executionWallTime = executionWallTime;
- this.retryTime = retryTime;
- this.processOutputsTime = processOutputsTime;
- this.inputBytes = inputBytes;
- this.inputFiles = inputFiles;
- this.memoryEstimateBytes = memoryEstimateBytes;
- }
-
private SpawnMetrics(Builder builder) {
this.execKind = builder.execKind;
this.totalTime = builder.totalTime;
@@ -278,7 +246,7 @@
/** Builder class for SpawnMetrics. */
public static class Builder {
- private ExecKind execKind = ExecKind.REMOTE;
+ private ExecKind execKind = null;
private Duration totalTime = Duration.ZERO;
private Duration parseTime = Duration.ZERO;
private Duration networkTime = Duration.ZERO;
@@ -293,7 +261,32 @@
private long inputFiles = 0;
private long memoryEstimateBytes = 0;
+ public static Builder forLocalExec() {
+ return forExec(ExecKind.LOCAL);
+ }
+
+ public static Builder forRemoteExec() {
+ return forExec(ExecKind.REMOTE);
+ }
+
+ public static Builder forWorkerExec() {
+ return forExec(ExecKind.WORKER);
+ }
+
+ public static Builder forOtherExec() {
+ return forExec(ExecKind.OTHER);
+ }
+
+ public static Builder forExec(ExecKind kind) {
+ return new Builder().setExecKind(kind);
+ }
+
+ // Make the constructor private to force users to set the ExecKind by using one of the factory
+ // methods.
+ private Builder() {}
+
public SpawnMetrics build() {
+ Preconditions.checkNotNull(execKind, "ExecKind must be explicitly set using `setExecKind`");
// TODO(ulfjack): Add consistency checks here?
return new SpawnMetrics(this);
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
index b33338a..d0e5ad3 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
@@ -126,7 +126,7 @@
MerkleTree merkleTree =
MerkleTree.build(inputMap, context.getMetadataProvider(), execRoot, digestUtil);
SpawnMetrics.Builder spawnMetrics =
- new SpawnMetrics.Builder()
+ SpawnMetrics.Builder.forRemoteExec()
.setInputBytes(merkleTree.getInputBytes())
.setInputFiles(merkleTree.getInputFiles());
Digest merkleTreeRoot = merkleTree.getRootDigest();
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
index 2b295d1..7966e08 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
@@ -213,7 +213,7 @@
final MerkleTree merkleTree =
MerkleTree.build(inputMap, context.getMetadataProvider(), execRoot, digestUtil);
SpawnMetrics.Builder spawnMetrics =
- new SpawnMetrics.Builder()
+ SpawnMetrics.Builder.forRemoteExec()
.setInputBytes(merkleTree.getInputBytes())
.setInputFiles(merkleTree.getInputFiles());
maybeWriteParamFilesLocally(spawn);
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComponent.java b/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComponent.java
index 080bbde..b5f599c 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComponent.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComponent.java
@@ -66,7 +66,7 @@
private final Artifact primaryOutput;
/** Spawn metrics for this action. */
- private SpawnMetrics phaseMaxMetrics = SpawnMetrics.EMPTY_REMOTE;
+ @Nullable private SpawnMetrics phaseMaxMetrics = null;
private AggregatedSpawnMetrics totalSpawnMetrics = AggregatedSpawnMetrics.EMPTY;
private Duration longestRunningTotalDuration = Duration.ZERO;
@@ -124,9 +124,9 @@
}
// If the phaseMaxMetrics has Duration, then we want to aggregate it to the total.
- if (!this.phaseMaxMetrics.totalTime().isZero()) {
+ if (this.phaseMaxMetrics != null && !this.phaseMaxMetrics.totalTime().isZero()) {
this.totalSpawnMetrics = this.totalSpawnMetrics.sumDurationsMaxOther(phaseMaxMetrics);
- this.phaseMaxMetrics = SpawnMetrics.EMPTY_REMOTE;
+ this.phaseMaxMetrics = null;
}
}
@@ -197,10 +197,13 @@
this.remote = true;
}
if (this.phaseChange) {
- this.totalSpawnMetrics = this.totalSpawnMetrics.sumDurationsMaxOther(phaseMaxMetrics);
+ if (this.phaseMaxMetrics != null) {
+ this.totalSpawnMetrics = this.totalSpawnMetrics.sumDurationsMaxOther(phaseMaxMetrics);
+ }
this.phaseMaxMetrics = metrics;
this.phaseChange = false;
- } else if (metrics.totalTime().compareTo(this.phaseMaxMetrics.totalTime()) > 0) {
+ } else if (this.phaseMaxMetrics == null
+ || metrics.totalTime().compareTo(this.phaseMaxMetrics.totalTime()) > 0) {
this.phaseMaxMetrics = metrics;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
index 50f1c35..ae7bcbd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
@@ -889,7 +889,7 @@
env.getListener()
.post(
new DiscoveredInputsEvent(
- new SpawnMetrics.Builder()
+ SpawnMetrics.Builder.forOtherExec()
.setParseTime(discoveredInputsDuration)
.setTotalTime(discoveredInputsDuration)
.build(),
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
index f227f14..f4f8631 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
@@ -173,9 +173,7 @@
SortedMap<PathFragment, HashCode> workerFiles =
WorkerFilesHash.getWorkerFilesWithHashes(
- spawn,
- context.getArtifactExpander(),
- context.getMetadataProvider());
+ spawn, context.getArtifactExpander(), context.getMetadataProvider());
HashCode workerFilesCombinedHash = WorkerFilesHash.getCombinedHash(workerFiles);
@@ -215,8 +213,7 @@
exitCode == 0 ? SpawnResult.Status.SUCCESS : SpawnResult.Status.NON_ZERO_EXIT)
.setWallTime(wallTime)
.setSpawnMetrics(
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.WORKER)
+ SpawnMetrics.Builder.forWorkerExec()
.setTotalTime(wallTime)
.setExecutionWallTime(wallTime)
.build())
diff --git a/src/test/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetricsTest.java b/src/test/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetricsTest.java
index 34ef58c..5505605 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetricsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/AggregatedSpawnMetricsTest.java
@@ -27,8 +27,7 @@
@Test
public void sumAllMetrics() throws Exception {
SpawnMetrics metrics1 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(1))
.setExecutionWallTime(Duration.ofSeconds(2))
.setInputBytes(10)
@@ -36,8 +35,7 @@
.setMemoryEstimateBytes(30)
.build();
SpawnMetrics metrics2 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(10))
.setExecutionWallTime(Duration.ofSeconds(20))
.setInputBytes(100)
@@ -59,8 +57,7 @@
@Test
public void sumDurationMetricsMaxOther() throws Exception {
SpawnMetrics metrics1 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(1))
.setExecutionWallTime(Duration.ofSeconds(2))
.setInputBytes(10)
@@ -68,8 +65,7 @@
.setMemoryEstimateBytes(30)
.build();
SpawnMetrics metrics2 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(10))
.setExecutionWallTime(Duration.ofSeconds(20))
.setInputBytes(100)
@@ -91,20 +87,11 @@
@Test
public void aggregatingMetrics_preservesExecKind() throws Exception {
SpawnMetrics metrics1 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.LOCAL)
- .setTotalTime(Duration.ofSeconds(1))
- .build();
+ SpawnMetrics.Builder.forLocalExec().setTotalTime(Duration.ofSeconds(1)).build();
SpawnMetrics metrics2 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
- .setTotalTime(Duration.ofSeconds(2))
- .build();
+ SpawnMetrics.Builder.forRemoteExec().setTotalTime(Duration.ofSeconds(2)).build();
SpawnMetrics metrics3 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.WORKER)
- .setTotalTime(Duration.ofSeconds(3))
- .build();
+ SpawnMetrics.Builder.forWorkerExec().setTotalTime(Duration.ofSeconds(3)).build();
AggregatedSpawnMetrics aggregated = AggregatedSpawnMetrics.EMPTY;
aggregated = aggregated.sumAllMetrics(metrics1);
@@ -122,21 +109,18 @@
@Test
public void toString_printsOnlyRemote() throws Exception {
SpawnMetrics metrics1 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.LOCAL)
+ SpawnMetrics.Builder.forLocalExec()
.setTotalTime(Duration.ofSeconds(1))
.setExecutionWallTime(Duration.ofSeconds(1))
.build();
SpawnMetrics metrics2 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(2))
.setNetworkTime(Duration.ofSeconds(1))
.setExecutionWallTime(Duration.ofSeconds(1))
.build();
SpawnMetrics metrics3 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.WORKER)
+ SpawnMetrics.Builder.forWorkerExec()
.setTotalTime(Duration.ofSeconds(3))
.setQueueTime(Duration.ofSeconds(1))
.setExecutionWallTime(Duration.ofSeconds(2))
diff --git a/src/test/java/com/google/devtools/build/lib/actions/SpawnMetricsTest.java b/src/test/java/com/google/devtools/build/lib/actions/SpawnMetricsTest.java
index 0f3c1ae..75dee98 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/SpawnMetricsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/SpawnMetricsTest.java
@@ -27,8 +27,7 @@
@Test
public void builder_addDurationsNonDurations() throws Exception {
SpawnMetrics metrics1 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(1))
.setExecutionWallTime(Duration.ofSeconds(2))
.setInputBytes(10)
@@ -36,8 +35,7 @@
.setMemoryEstimateBytes(30)
.build();
SpawnMetrics metrics2 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(10))
.setExecutionWallTime(Duration.ofSeconds(20))
.setInputBytes(100)
@@ -46,8 +44,7 @@
.build();
SpawnMetrics result =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.addDurations(metrics1)
.addDurations(metrics2)
.addNonDurations(metrics1)
@@ -64,8 +61,7 @@
@Test
public void builder_addDurationsMaxNonDurations() throws Exception {
SpawnMetrics metrics1 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(1))
.setExecutionWallTime(Duration.ofSeconds(2))
.setInputBytes(10)
@@ -73,8 +69,7 @@
.setMemoryEstimateBytes(30)
.build();
SpawnMetrics metrics2 =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.setTotalTime(Duration.ofSeconds(10))
.setExecutionWallTime(Duration.ofSeconds(20))
.setInputBytes(100)
@@ -83,8 +78,7 @@
.build();
SpawnMetrics result =
- new SpawnMetrics.Builder()
- .setExecKind(SpawnMetrics.ExecKind.REMOTE)
+ SpawnMetrics.Builder.forRemoteExec()
.addDurations(metrics1)
.addDurations(metrics2)
.maxNonDurations(metrics1)
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java
index ad1f45f..aac8abd 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java
@@ -975,7 +975,7 @@
@Test
public void accountingAddsDurationsForStages() {
SpawnMetrics.Builder builder =
- new SpawnMetrics.Builder()
+ SpawnMetrics.Builder.forRemoteExec()
.setQueueTime(Duration.ofSeconds(1))
.setSetupTime(Duration.ofSeconds(2))
.setExecutionWallTime(Duration.ofSeconds(2))
@@ -1026,10 +1026,7 @@
}
private RemoteSpawnRunner newSpawnRunner() {
- return newSpawnRunner(
- executor,
- /* reporter= */ null,
- /* topLevelOutputs= */ ImmutableSet.of());
+ return newSpawnRunner(executor, /* reporter= */ null, /* topLevelOutputs= */ ImmutableSet.of());
}
private RemoteSpawnRunner newSpawnRunner(Reporter reporter) {