Skip to content

Commit 0e099d9

Browse files
Googlercopybara-github
authored andcommitted
Include input discovery time in the execution graph.
The CriticalPathComputer includes it as parse time, but here, we can add another field. PiperOrigin-RevId: 500757360 Change-Id: I954fcb90b575a0bfd535dc190f7958fc689ae84f
1 parent 3d29b2e commit 0e099d9

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.google.devtools.build.lib.actions.ActionMiddlemanEvent;
3232
import com.google.devtools.build.lib.actions.Artifact;
3333
import com.google.devtools.build.lib.actions.CachedActionEvent;
34+
import com.google.devtools.build.lib.actions.DiscoveredInputsEvent;
3435
import com.google.devtools.build.lib.actions.ExecutionGraph;
3536
import com.google.devtools.build.lib.actions.RunfilesSupplier;
3637
import com.google.devtools.build.lib.actions.Spawn;
@@ -263,6 +264,17 @@ public void buildComplete(BuildCompleteEvent event) {
263264
}
264265
}
265266
}
267+
268+
/** Records the input discovery time. */
269+
@Subscribe
270+
@AllowConcurrentEvents
271+
public void discoverInputs(DiscoveredInputsEvent event) {
272+
ActionDumpWriter localWriter = writer;
273+
if (localWriter != null) {
274+
localWriter.enqueue(event);
275+
}
276+
}
277+
266278
/** Record an action that didn't publish any SpawnExecutedEvents. */
267279
@Subscribe
268280
@AllowConcurrentEvents
@@ -401,11 +413,23 @@ private ExecutionGraph.Node toProto(SpawnExecutedEvent event) {
401413
SpawnMetrics metrics = spawnResult.getMetrics();
402414
spawnResult = null;
403415
long totalMillis = metrics.totalTime().toMillis();
416+
417+
long discoverInputsMillis = 0;
418+
ActionInput firstOutput = getFirstOutput(spawn.getResourceOwner(), spawn.getOutputFiles());
419+
Duration discoverInputsTime = outputToDiscoverInputsTime.get(firstOutput);
420+
if (discoverInputsTime != null) {
421+
// Remove this so we don't count it again later, if an action has multiple spawns.
422+
outputToDiscoverInputsTime.remove(firstOutput);
423+
discoverInputsMillis = discoverInputsTime.toMillis();
424+
totalMillis += discoverInputsMillis;
425+
}
426+
404427
ExecutionGraph.Metrics.Builder metricsBuilder =
405428
ExecutionGraph.Metrics.newBuilder()
406429
.setStartTimestampMillis(startMillis)
407430
.setDurationMillis((int) totalMillis)
408431
.setFetchMillis((int) metrics.fetchTime().toMillis())
432+
.setDiscoverInputsMillis((int) discoverInputsMillis)
409433
.setParseMillis((int) metrics.parseTime().toMillis())
410434
.setProcessMillis((int) metrics.executionWallTime().toMillis())
411435
.setQueueMillis((int) metrics.queueTime().toMillis())
@@ -544,6 +568,7 @@ private NodeInfo(int index, long finishMs) {
544568
private final BugReporter bugReporter;
545569
private final boolean localLockFreeOutputEnabled;
546570
private final Map<ActionInput, NodeInfo> outputToNode = new ConcurrentHashMap<>();
571+
private final Map<ActionInput, Duration> outputToDiscoverInputsTime = new ConcurrentHashMap<>();
547572
private final DependencyInfo depType;
548573
private final AtomicInteger nextIndex = new AtomicInteger(0);
549574

@@ -607,6 +632,20 @@ void enqueue(byte[] entry) {
607632
blockedMillis.addAndGet(sw.elapsed().toMillis());
608633
}
609634

635+
void enqueue(DiscoveredInputsEvent event) {
636+
// The other times from SpawnMetrics are not needed. The only instance of
637+
// DiscoveredInputsEvent sets only total and parse time, and to the same value.
638+
var totalTime = event.getMetrics().totalTime();
639+
var firstOutput = getFirstOutput(event.getAction(), event.getAction().getOutputs());
640+
var sum = outputToDiscoverInputsTime.get(firstOutput);
641+
if (sum != null) {
642+
sum = sum.plus(totalTime);
643+
} else {
644+
sum = totalTime;
645+
}
646+
outputToDiscoverInputsTime.put(firstOutput, sum);
647+
}
648+
610649
void enqueue(Action action, long startMillis) {
611650
// This is here just to capture actions which don't have spawns. If we already know about
612651
// an output, don't also include it again.

src/main/protobuf/execution_graph.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ message Metrics {
7979
int32 setup_millis = 8;
8080
int32 process_outputs_millis = 9;
8181
int32 queue_millis = 10;
82+
int32 discover_inputs_millis = 14;
8283

8384
// Total time spent on failed attempts.
8485
int32 retry_millis = 11;

src/test/java/com/google/devtools/build/lib/runtime/ExecutionGraphModuleTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.google.devtools.build.lib.actions.Artifact;
3535
import com.google.devtools.build.lib.actions.ArtifactRoot;
3636
import com.google.devtools.build.lib.actions.ArtifactRoot.RootType;
37+
import com.google.devtools.build.lib.actions.DiscoveredInputsEvent;
3738
import com.google.devtools.build.lib.actions.ExecutionGraph;
3839
import com.google.devtools.build.lib.actions.ResourceSet;
3940
import com.google.devtools.build.lib.actions.SimpleSpawn;
@@ -145,6 +146,57 @@ public void testOneSpawn() throws IOException {
145146
assertThat(nodes.get(0).getDependentIndexList()).isEmpty();
146147
}
147148

149+
@Test
150+
public void testSpawnWithDiscoverInputs() throws IOException {
151+
UUID uuid = UUID.randomUUID();
152+
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
153+
Spawn spawn =
154+
new SimpleSpawn(
155+
new FakeOwnerWithPrimaryOutput(
156+
"Mnemonic", "Progress message", "//foo", "output/foo/out"),
157+
ImmutableList.of("cmd"),
158+
ImmutableMap.of("env", "value"),
159+
ImmutableMap.of("exec", "value"),
160+
/* inputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
161+
/* outputs= */ ImmutableSet.of(createOutputArtifact("output/foo/out")),
162+
ResourceSet.ZERO);
163+
SpawnResult result =
164+
new SpawnResult.Builder()
165+
.setRunnerName("local")
166+
.setStatus(Status.SUCCESS)
167+
.setExitCode(0)
168+
.setSpawnMetrics(
169+
SpawnMetrics.Builder.forLocalExec()
170+
.setTotalTime(Duration.ofMillis(1234L))
171+
.setExecutionWallTime(Duration.ofMillis(2345L))
172+
.setProcessOutputsTime(Duration.ofMillis(3456L))
173+
.setParseTime(Duration.ofMillis(2000))
174+
.build())
175+
.build();
176+
startLogging(eventBus, uuid, buffer, DependencyInfo.NONE);
177+
Instant startTimeInstant = Instant.ofEpochMilli(999888777L);
178+
module.discoverInputs(
179+
new DiscoveredInputsEvent(
180+
SpawnMetrics.Builder.forOtherExec()
181+
.setParseTime(Duration.ofMillis(987))
182+
.setTotalTime(Duration.ofMillis(987))
183+
.build(),
184+
new ActionsTestUtil.NullAction(createOutputArtifact("output/foo/out")),
185+
0));
186+
module.spawnExecuted(new SpawnExecutedEvent(spawn, result, startTimeInstant));
187+
module.buildComplete(
188+
new BuildCompleteEvent(new BuildResult(startTimeInstant.toEpochMilli() + 1000)));
189+
190+
ImmutableList<ExecutionGraph.Node> nodes = parse(buffer);
191+
ExecutionGraph.Metrics metrics = nodes.get(0).getMetrics();
192+
assertThat(metrics.getDurationMillis()).isEqualTo(2221);
193+
assertThat(metrics.getFetchMillis()).isEqualTo(0);
194+
assertThat(metrics.getProcessMillis()).isEqualTo(2345);
195+
assertThat(metrics.getProcessOutputsMillis()).isEqualTo(3456);
196+
assertThat(metrics.getParseMillis()).isEqualTo(2000);
197+
assertThat(metrics.getDiscoverInputsMillis()).isEqualTo(987);
198+
}
199+
148200
@Test
149201
public void actionDepsWithThreeSpawns() throws IOException {
150202
UUID uuid = UUID.randomUUID();

0 commit comments

Comments
 (0)