Add finish time in events which are used to compute critical path.
Before that change we used clock to compute finish time in `CriticalPathComputer` for events `ActionMiddlemanEvent`, `CachedActionEvent`, `ActionCompletionEvent`. This time could be different from real finish time because subscribers execute their code serially. So it could be delay between real action completion and event processing.
PiperOrigin-RevId: 540248815
Change-Id: Ie6cb701b135ac3b4cd3edb6be5251e30edbb4823
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionCompletionEvent.java b/src/main/java/com/google/devtools/build/lib/actions/ActionCompletionEvent.java
index f0c4c78..8086518 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionCompletionEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionCompletionEvent.java
@@ -19,13 +19,18 @@
/** An event that is fired after an action completes (either successfully or not). */
public final class ActionCompletionEvent implements Postable {
- private final long relativeActionStartTime;
+ private final long relativeActionStartTimeNanos;
+ private final long finishTimeNanos;
private final Action action;
private final ActionLookupData actionLookupData;
public ActionCompletionEvent(
- long relativeActionStartTime, Action action, ActionLookupData actionLookupData) {
- this.relativeActionStartTime = relativeActionStartTime;
+ long relativeActionStartTimeNanos,
+ long finishTimeNanos,
+ Action action,
+ ActionLookupData actionLookupData) {
+ this.relativeActionStartTimeNanos = relativeActionStartTimeNanos;
+ this.finishTimeNanos = finishTimeNanos;
this.action = action;
this.actionLookupData = actionLookupData;
}
@@ -37,8 +42,12 @@
return action;
}
- public long getRelativeActionStartTime() {
- return relativeActionStartTime;
+ public long getRelativeActionStartTimeNanos() {
+ return relativeActionStartTimeNanos;
+ }
+
+ public long getFinishTimeNanos() {
+ return finishTimeNanos;
}
public ActionLookupData getActionLookupData() {
@@ -48,7 +57,8 @@
@Override
public String toString() {
return MoreObjects.toStringHelper("ActionCompletionEvent")
- .add("relativeActionStartTime", relativeActionStartTime)
+ .add("relativeActionStartTimeNanos", relativeActionStartTimeNanos)
+ .add("finishTimeNanos", finishTimeNanos)
.add("action", action)
.add("actionLookupData", actionLookupData)
.toString();
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionMiddlemanEvent.java b/src/main/java/com/google/devtools/build/lib/actions/ActionMiddlemanEvent.java
index a27d0c6..52613e0 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionMiddlemanEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionMiddlemanEvent.java
@@ -25,20 +25,22 @@
private final Action action;
private final long nanoTimeStart;
+ private final long nanoTimeFinish;
/**
* Create an event for action that has been started.
*
* @param action the middleman action.
* @param nanoTimeStart the time when the action was started. This allow us to record more
- * accurately the time spent by the middleman action, since even for middleman actions we execute
- * some.
+ * accurately the time spent by the middleman action, since even for middleman actions we
+ * execute some.
*/
- public ActionMiddlemanEvent(Action action, long nanoTimeStart) {
+ public ActionMiddlemanEvent(Action action, long nanoTimeStart, long nanoTimeFinish) {
Preconditions.checkArgument(action.getActionType().isMiddleman(),
"Only middleman actions should be passed: %s", action);
this.action = action;
this.nanoTimeStart = nanoTimeStart;
+ this.nanoTimeFinish = nanoTimeFinish;
}
/**
@@ -52,4 +54,7 @@
return nanoTimeStart;
}
+ public long getNanoTimeFinish() {
+ return nanoTimeFinish;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/CachedActionEvent.java b/src/main/java/com/google/devtools/build/lib/actions/CachedActionEvent.java
index 28318e0..ce5bac6 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/CachedActionEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/CachedActionEvent.java
@@ -21,18 +21,20 @@
private final Action action;
private final long nanoTimeStart;
+ private final long nanoTimeFinish;
/**
* Create an event for an action that was cached.
*
* @param action the cached action
- * @param nanoTimeStart the time when the action was started. This allow us to
- * record more accurately the time spend by the action, since we execute some code before
- * deciding if we execute the action or not.
+ * @param nanoTimeStart the time when the action was started. This allow us to record more
+ * accurately the time spend by the action, since we execute some code before deciding if we
+ * execute the action or not.
*/
- public CachedActionEvent(Action action, long nanoTimeStart) {
+ public CachedActionEvent(Action action, long nanoTimeStart, long nanoTimeFinish) {
this.action = action;
this.nanoTimeStart = nanoTimeStart;
+ this.nanoTimeFinish = nanoTimeFinish;
}
public Action getAction() {
@@ -42,4 +44,8 @@
public long getNanoTimeStart() {
return nanoTimeStart;
}
+
+ public long getNanoTimeFinish() {
+ return nanoTimeFinish;
+ }
}
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 9e75fb2..86328fd 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
@@ -230,7 +230,7 @@
ActionStats actionStats =
actionStatsMap.computeIfAbsent(event.getAction().getMnemonic(), ActionStats::new);
actionStats.numActions.incrementAndGet();
- actionStats.firstStarted.accumulate(event.getRelativeActionStartTime());
+ actionStats.firstStarted.accumulate(event.getRelativeActionStartTimeNanos());
actionStats.lastEnded.accumulate(BlazeClock.nanoTime());
spawnStats.incrementActionCount();
}
diff --git a/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/CriticalPathComputer.java b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/CriticalPathComputer.java
index f9f8464..6e5ad22 100644
--- a/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/CriticalPathComputer.java
+++ b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/CriticalPathComputer.java
@@ -36,7 +36,6 @@
import com.google.devtools.build.lib.actions.SpawnExecutedEvent;
import com.google.devtools.build.lib.actions.SpawnMetrics;
import com.google.devtools.build.lib.actions.SpawnResult;
-import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.skyframe.rewinding.ActionRewoundEvent;
import java.time.Duration;
import java.util.Comparator;
@@ -81,11 +80,8 @@
/** Maximum critical path found. */
private final AtomicReference<CriticalPathComponent> maxCriticalPath = new AtomicReference<>();
- private final Clock clock;
-
- public CriticalPathComputer(ActionKeyContext actionKeyContext, Clock clock) {
+ public CriticalPathComputer(ActionKeyContext actionKeyContext) {
this.actionKeyContext = actionKeyContext;
- this.clock = clock;
}
/**
@@ -251,7 +247,8 @@
Action action = event.getAction();
CriticalPathComponent component =
tryAddComponent(createComponent(action, event.getNanoTimeStart()));
- finalizeActionStat(event.getNanoTimeStart(), action, component, "middleman action");
+ finalizeActionStat(
+ event.getNanoTimeStart(), event.getNanoTimeFinish(), action, component, "middleman action");
}
/**
@@ -312,7 +309,8 @@
Action action = event.getAction();
CriticalPathComponent component =
tryAddComponent(createComponent(action, event.getNanoTimeStart()));
- finalizeActionStat(event.getNanoTimeStart(), action, component, "action cache hit");
+ finalizeActionStat(
+ event.getNanoTimeStart(), event.getNanoTimeFinish(), action, component, "action cache hit");
}
/**
@@ -326,7 +324,8 @@
CriticalPathComponent component =
Preconditions.checkNotNull(
outputArtifactToComponent.get(action.getPrimaryOutput()), action);
- finalizeActionStat(event.getRelativeActionStartTime(), action, component, "");
+ finalizeActionStat(
+ event.getRelativeActionStartTimeNanos(), event.getFinishTimeNanos(), action, component, "");
}
/**
@@ -340,7 +339,9 @@
CriticalPathComponent component =
Preconditions.checkNotNull(outputArtifactToComponent.get(action.getPrimaryOutput()));
component.finishActionExecution(
- event.getRelativeActionStartTime(), clock.nanoTime(), "action rewound");
+ event.getRelativeActionStartTimeNanos(),
+ event.getRelativeActionFinishTimeNanos(),
+ "action rewound");
}
/** Maximum critical path component found during the build. */
@@ -349,8 +350,11 @@
}
private void finalizeActionStat(
- long startTimeNanos, Action action, CriticalPathComponent component, String finalizeReason) {
- long finishTimeNanos = clock.nanoTime();
+ long startTimeNanos,
+ long finishTimeNanos,
+ Action action,
+ CriticalPathComponent component,
+ String finalizeReason) {
for (Artifact input : action.getInputs().toList()) {
addArtifactDependency(component, input, finishTimeNanos);
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java b/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java
index 9a1fc76..74301d1 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java
@@ -92,7 +92,7 @@
enabled = env.getOptions().getOptions(ExecutionOptions.class).enableCriticalPathProfiling;
statsSummary = env.getOptions().getOptions(ExecutionOptions.class).statsSummary;
if (enabled) {
- criticalPathComputer = new CriticalPathComputer(actionKeyContext, BlazeClock.instance());
+ criticalPathComputer = new CriticalPathComputer(actionKeyContext);
eventBus.register(criticalPathComputer);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java b/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java
index 02fc322..658083d 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java
@@ -320,8 +320,9 @@
@Subscribe
@AllowConcurrentEvents
public void actionComplete(ActionCompletionEvent event) {
+ // TODO(vanja): handle finish time in ActionCompletionEvent
if (options.logMissedActions) {
- actionEvent(event.getAction(), event.getRelativeActionStartTime());
+ actionEvent(event.getAction(), event.getRelativeActionStartTimeNanos());
}
}
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 0d078be..1fe0c2f 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
@@ -420,7 +420,7 @@
LostInputsActionExecutionException e,
ActionLookupData actionLookupData,
Action action,
- long actionStartTime,
+ long actionStartTimeNanos,
Environment env,
NestedSet<Artifact> allInputs,
Iterable<SkyKey> depKeys,
@@ -483,7 +483,8 @@
}
if (e.isActionStartedEventAlreadyEmitted()) {
- env.getListener().post(new ActionRewoundEvent(actionStartTime, action));
+ env.getListener()
+ .post(new ActionRewoundEvent(actionStartTimeNanos, BlazeClock.nanoTime(), action));
}
skyframeActionExecutor.resetRewindingAction(actionLookupData, action, lostDiscoveredInputs);
for (Action actionToRestart : rewindPlan.getAdditionalActionsToRestart()) {
@@ -496,7 +497,9 @@
// ActionCompletionEvent because it hoped rewinding would fix things. Because it won't, this
// must emit one to compensate.
env.getListener()
- .post(new ActionCompletionEvent(actionStartTime, action, actionLookupData));
+ .post(
+ new ActionCompletionEvent(
+ actionStartTimeNanos, BlazeClock.nanoTime(), action, actionLookupData));
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
index 5d70ff3..f15cd79 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
@@ -79,6 +79,7 @@
import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
import com.google.devtools.build.lib.buildtool.BuildRequestOptions;
+import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Event;
@@ -673,7 +674,8 @@
boolean eventPosted = false;
// Notify BlazeRuntimeStatistics about the action middleman 'execution'.
if (action.getActionType().isMiddleman()) {
- eventHandler.post(new ActionMiddlemanEvent(action, actionStartTime));
+ eventHandler.post(
+ new ActionMiddlemanEvent(action, actionStartTime, BlazeClock.nanoTime()));
eventPosted = true;
}
@@ -723,7 +725,7 @@
/* filesetOutputSymlinksForMetrics= */ null,
/* isActionCacheHitForMetrics= */ true);
if (!eventPosted) {
- eventHandler.post(new CachedActionEvent(action, actionStartTime));
+ eventHandler.post(new CachedActionEvent(action, actionStartTime, BlazeClock.nanoTime()));
}
}
} catch (UserExecException e) {
@@ -953,7 +955,7 @@
private final class ActionRunner extends ActionStep {
private final Action action;
private final ActionMetadataHandler metadataHandler;
- private final long actionStartTime;
+ private final long actionStartTimeNanos;
private final ActionExecutionContext actionExecutionContext;
private final ActionLookupData actionLookupData;
@Nullable private final ActionExecutionStatusReporter statusReporter;
@@ -962,13 +964,13 @@
ActionRunner(
Action action,
ActionMetadataHandler metadataHandler,
- long actionStartTime,
+ long actionStartTimeNanos,
ActionExecutionContext actionExecutionContext,
ActionLookupData actionLookupData,
ActionPostprocessing postprocessing) {
this.action = action;
this.metadataHandler = metadataHandler;
- this.actionStartTime = actionStartTime;
+ this.actionStartTimeNanos = actionStartTimeNanos;
this.actionExecutionContext = actionExecutionContext;
this.actionLookupData = actionLookupData;
this.statusReporter = statusReporterRef.get();
@@ -1008,7 +1010,7 @@
boolean lostInputs = false;
try {
- ActionStartedEvent event = new ActionStartedEvent(action, actionStartTime);
+ ActionStartedEvent event = new ActionStartedEvent(action, actionStartTimeNanos);
if (statusReporter != null) {
statusReporter.updateStatus(event);
}
@@ -1074,7 +1076,9 @@
statusReporter.remove(action);
}
if (postActionCompletionEvent) {
- eventHandler.post(new ActionCompletionEvent(actionStartTime, action, actionLookupData));
+ eventHandler.post(
+ new ActionCompletionEvent(
+ actionStartTimeNanos, BlazeClock.nanoTime(), action, actionLookupData));
}
String message = action.getProgressMessage();
if (message != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/rewinding/ActionRewoundEvent.java b/src/main/java/com/google/devtools/build/lib/skyframe/rewinding/ActionRewoundEvent.java
index fe0ac35..8eb5b7f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/rewinding/ActionRewoundEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/rewinding/ActionRewoundEvent.java
@@ -22,7 +22,8 @@
*/
public final class ActionRewoundEvent implements Postable {
- private final long relativeActionStartTime;
+ private final long relativeActionStartTimeNanos;
+ private final long relativeActionFinishTimeNanos;
private final Action failedRewoundAction;
/**
@@ -32,14 +33,23 @@
* @param relativeActionStartTime a nanotime taken before action execution began
* @param failedRewoundAction the failed action.
*/
- public ActionRewoundEvent(long relativeActionStartTime, Action failedRewoundAction) {
- this.relativeActionStartTime = relativeActionStartTime;
+ public ActionRewoundEvent(
+ long relativeActionStartTimeNanos,
+ long relativeActionFinishTimeNanos,
+ Action failedRewoundAction) {
+ this.relativeActionStartTimeNanos = relativeActionStartTimeNanos;
+ this.relativeActionFinishTimeNanos = relativeActionFinishTimeNanos;
this.failedRewoundAction = failedRewoundAction;
}
/** Returns a nanotime taken before action execution began. */
- public long getRelativeActionStartTime() {
- return relativeActionStartTime;
+ public long getRelativeActionStartTimeNanos() {
+ return relativeActionStartTimeNanos;
+ }
+
+ /** Returns a nanotime taken after action execution finished. */
+ public long getRelativeActionFinishTimeNanos() {
+ return relativeActionFinishTimeNanos;
}
/** Returns the associated action. */