A CriticalPathComponent's input discovery step is not categorized so there is a discrepancy in runtime and metrics provided. Now input discovery will be categorized as parse time.
RELNOTES: An action's discover inputs runtime metrics is now categorized as parse time on the CriticalPathComponent.
PiperOrigin-RevId: 281086930
diff --git a/src/main/java/com/google/devtools/build/lib/actions/DiscoveredInputsEvent.java b/src/main/java/com/google/devtools/build/lib/actions/DiscoveredInputsEvent.java
new file mode 100644
index 0000000..fd1a36b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/actions/DiscoveredInputsEvent.java
@@ -0,0 +1,42 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.actions;
+
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+
+/** Event for passing SpawnMetrics for the discover inputs phase. */
+public class DiscoveredInputsEvent implements ExtendedEventHandler.ProgressLike {
+ private final SpawnMetrics metrics;
+ private final Action action;
+ private final long startTimeNanos;
+
+ public DiscoveredInputsEvent(SpawnMetrics metrics, Action action, long startTimeNanos) {
+ this.metrics = metrics;
+ this.action = action;
+ this.startTimeNanos = startTimeNanos;
+ }
+
+ public SpawnMetrics getMetrics() {
+ return metrics;
+ }
+
+ public Action getAction() {
+ return action;
+ }
+
+ public long getStartTimeNanos() {
+ return startTimeNanos;
+ }
+}
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 c6362324..d08a908 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
@@ -165,26 +165,26 @@
}
/**
- * An action can run multiple spawns. Those calls can be sequential or parallel. If it is a
- * sequence of calls we should aggregate the metrics by collecting all the SpawnResults, if they
- * are run in parallel we should keep the maximum runtime spawn. We will also set the
- * longestPhaseSpawnRunnerName to the longest running spawn runner name across all phases.
+ * An action can run multiple spawns. Those calls can be sequential or parallel. If action is a
+ * sequence of calls we aggregate the SpawnMetrics of all the SpawnResults. If there are multiples
+ * of the same action run in parallel, we keep the maximum runtime SpawnMetrics. We will also set
+ * the longestPhaseSpawnRunnerName to the longest running spawn runner name across all phases if
+ * it exists.
*/
- void addSpawnResult(SpawnResult spawnResult) {
+ void addSpawnResult(SpawnMetrics metrics, @Nullable String runnerName) {
if (this.phaseChange) {
this.totalSpawnMetrics =
SpawnMetrics.aggregateMetrics(
ImmutableList.of(this.totalSpawnMetrics, this.phaseMaxMetrics), true);
- this.phaseMaxMetrics = spawnResult.getMetrics();
+ this.phaseMaxMetrics = metrics;
this.phaseChange = false;
- } else if (spawnResult.getMetrics().totalTime().compareTo(this.phaseMaxMetrics.totalTime())
- > 0) {
- this.phaseMaxMetrics = spawnResult.getMetrics();
+ } else if (metrics.totalTime().compareTo(this.phaseMaxMetrics.totalTime()) > 0) {
+ this.phaseMaxMetrics = metrics;
}
- if (spawnResult.getMetrics().totalTime().compareTo(this.longestRunningTotalDuration) > 0) {
- this.longestPhaseSpawnRunnerName = spawnResult.getRunnerName();
- this.longestRunningTotalDuration = spawnResult.getMetrics().totalTime();
+ if (runnerName != null && metrics.totalTime().compareTo(this.longestRunningTotalDuration) > 0) {
+ this.longestPhaseSpawnRunnerName = runnerName;
+ this.longestRunningTotalDuration = metrics.totalTime();
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComputer.java b/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComputer.java
index 632acd5..59411d3 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComputer.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CriticalPathComputer.java
@@ -30,6 +30,7 @@
import com.google.devtools.build.lib.actions.Actions;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.CachedActionEvent;
+import com.google.devtools.build.lib.actions.DiscoveredInputsEvent;
import com.google.devtools.build.lib.actions.SpawnExecutedEvent;
import com.google.devtools.build.lib.actions.SpawnMetrics;
import com.google.devtools.build.lib.actions.SpawnResult;
@@ -132,6 +133,7 @@
return outputArtifactToComponent;
}
+ /** Changes the phase of the action */
@Subscribe
@AllowConcurrentEvents
public void nextCriticalPathPhase(SpawnExecutedEvent.ChangePhase phase) {
@@ -158,7 +160,7 @@
Preconditions.checkNotNull(outputArtifactToComponent.get(primaryOutput));
SpawnResult spawnResult = event.getSpawnResult();
- stats.addSpawnResult(spawnResult);
+ stats.addSpawnResult(spawnResult.getMetrics(), spawnResult.getRunnerName());
}
/** Returns the list of components using the most memory. */
@@ -194,8 +196,19 @@
.map((e) -> e.getValue());
}
+ /** Creates a CriticalPathComponent and adds the duration of input discovery and changes phase. */
+ @Subscribe
+ @AllowConcurrentEvents
+ public void discoverInputs(DiscoveredInputsEvent event) {
+ CriticalPathComponent stats =
+ tryAddComponent(createComponent(event.getAction(), event.getStartTimeNanos()));
+ stats.addSpawnResult(event.getMetrics(), null);
+ stats.changePhase();
+ }
+
/**
- * Record an action that has started to run.
+ * Record an action that has started to run. If the CriticalPathComponent has not been created,
+ * initialize it.
*
* @param event information about the started action
*/
@@ -277,8 +290,8 @@
@AllowConcurrentEvents
public void actionCached(CachedActionEvent event) {
Action action = event.getAction();
- CriticalPathComponent component
- = tryAddComponent(createComponent(action, event.getNanoTimeStart()));
+ CriticalPathComponent component =
+ tryAddComponent(createComponent(action, event.getNanoTimeStart()));
finalizeActionStat(event.getNanoTimeStart(), action, component);
}
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 852a4d3..c685193 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
@@ -38,6 +38,7 @@
import com.google.devtools.build.lib.actions.AlreadyReportedActionExecutionException;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactPathResolver;
+import com.google.devtools.build.lib.actions.DiscoveredInputsEvent;
import com.google.devtools.build.lib.actions.FileArtifactValue;
import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
import com.google.devtools.build.lib.actions.LostInputsActionExecutionException;
@@ -45,6 +46,7 @@
import com.google.devtools.build.lib.actions.MissingInputFileException;
import com.google.devtools.build.lib.actions.NotifyOnActionCacheHit;
import com.google.devtools.build.lib.actions.PackageRootResolver;
+import com.google.devtools.build.lib.actions.SpawnMetrics;
import com.google.devtools.build.lib.actionsketch.ActionSketch;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.causes.Cause;
@@ -78,6 +80,7 @@
import com.google.devtools.build.skyframe.ValueOrException;
import com.google.devtools.build.skyframe.ValueOrException2;
import java.io.IOException;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -820,6 +823,10 @@
e,
action,
/*catastrophe=*/ false);
+ } finally {
+ state.discoveredInputsDuration =
+ state.discoveredInputsDuration.plus(
+ Duration.ofNanos(BlazeClock.nanoTime() - actionStartTime));
}
Preconditions.checkState(
env.valuesMissing() == (state.discoveredInputs == null),
@@ -855,6 +862,16 @@
// Set the MetadataHandler to accept output information.
metadataHandler.discardOutputMetadata();
}
+ // When discover inputs completes, post an event with the duration values.
+ env.getListener()
+ .post(
+ new DiscoveredInputsEvent(
+ new SpawnMetrics.Builder()
+ .setParseTime(state.discoveredInputsDuration)
+ .setTotalTime(state.discoveredInputsDuration)
+ .build(),
+ action,
+ actionStartTime));
}
try {
@@ -1332,6 +1349,7 @@
Token token = null;
Iterable<Artifact> discoveredInputs = null;
FileSystem actionFileSystem = null;
+ Duration discoveredInputsDuration = Duration.ZERO;
/**
* Stores the ArtifactNestedSetKeys created from the inputs of this actions. Objective: avoid