Skip to content

Commit 97e96f4

Browse files
bazel-iofmeum
andauthored
[9.0.0] Fix counting of internal actions (bazelbuild#27665)
Before this change, the number of internal actions was computed as `#actions - #spawns`, which is incorrect since a single action can run multiple spawns, not just zero or one. Also adds a comment explaining all the inconsistencies in the current stats output. Closes bazelbuild#27495. PiperOrigin-RevId: 831853687 Change-Id: I82f4dff578f32fac120211286da71ed1380e10e7 Commit bazelbuild@9f18c80 Co-authored-by: Fabian Meumertzheim <fabian@meumertzhe.im>
1 parent b2d8552 commit 97e96f4

File tree

3 files changed

+236
-68
lines changed

3 files changed

+236
-68
lines changed

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

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,34 @@ public class SpawnStats {
3939
private final ConcurrentHashMultiset<String> runners = ConcurrentHashMultiset.create();
4040
private final ConcurrentHashMap<String, String> runnerExecKinds = new ConcurrentHashMap<>();
4141
private final AtomicLong totalWallTimeMillis = new AtomicLong();
42-
private final AtomicInteger totalNumberOfActions = new AtomicInteger();
42+
// Counts all actions, where an action can run an arbitrary number of spawns (including zero).
43+
private final AtomicInteger allActionsCount = new AtomicInteger();
44+
// Counts internal actions, such as SymlinkTree actions, which are recognized by having zero
45+
// spawns.
46+
private final AtomicInteger nonInternalActionsCount = new AtomicInteger();
4347
private int actionCacheHitCount = 0;
4448

4549
public void countActionResult(ActionResult actionResult) {
50+
// This method is usually not called for internal actions with {@link ActionResult#EMPTY}, but
51+
// just in case, we double-check here.
52+
if (!actionResult.spawnResults().isEmpty()) {
53+
nonInternalActionsCount.incrementAndGet();
54+
}
4655
for (SpawnResult r : actionResult.spawnResults()) {
4756
storeRunnerExecKind(r);
48-
countRunnerName(r.getRunnerName());
57+
runners.add(r.getRunnerName());
4958
totalWallTimeMillis.addAndGet(r.getMetrics().executionWallTimeInMs());
5059
}
5160
}
5261

53-
public void countRunnerName(String runner) {
54-
runners.add(runner);
55-
}
56-
5762
private void storeRunnerExecKind(SpawnResult r) {
5863
String name = r.getRunnerName();
5964
String execKind = r.getMetrics().execKind().toString();
6065
runnerExecKinds.put(name, execKind);
6166
}
6267

6368
public void incrementActionCount() {
64-
totalNumberOfActions.incrementAndGet();
69+
allActionsCount.incrementAndGet();
6570
}
6671

6772
public long getTotalWallTimeMillis() {
@@ -84,9 +89,9 @@ public ImmutableMap<String, Integer> getSummary() {
8489
*/
8590
public ImmutableMap<String, Integer> getSummary(ImmutableList<String> reportFirst) {
8691
ImmutableMap.Builder<String, Integer> result = ImmutableMap.builder();
87-
int numActionsWithoutInternal = runners.size();
88-
int numActionsTotal = totalNumberOfActions.get();
89-
result.put("total", numActionsTotal);
92+
int numNonInternalActions = nonInternalActionsCount.get();
93+
int numAllActions = allActionsCount.get();
94+
result.put("total", numAllActions);
9095

9196
// First report cache results.
9297
if (actionCacheHitCount > 0) {
@@ -100,8 +105,10 @@ public ImmutableMap<String, Integer> getSummary(ImmutableList<String> reportFirs
100105
}
101106

102107
// Account for internal actions such as SymlinkTree.
103-
if (numActionsWithoutInternal < numActionsTotal) {
104-
result.put("internal", numActionsTotal - numActionsWithoutInternal);
108+
// This condition is always fulfilled if {@link #incrementActionCount} is called for each
109+
// action for which {@link #countActionResult} is called eventually.
110+
if (numNonInternalActions < numAllActions) {
111+
result.put("internal", numAllActions - numNonInternalActions);
105112
}
106113

107114
// Sort the rest alphabetically
@@ -120,6 +127,17 @@ public String getExecKindFor(String runnerName) {
120127
}
121128

122129
public static String convertSummaryToString(ImmutableMap<String, Integer> spawnSummary) {
130+
// This summary is misleading in a number of ways:
131+
// - The "processes" count is actually the number of actions, not spawns.
132+
// - Even if it were the number of spawns, the "* cache hit" runners do not correspond to
133+
// processes executed, but rather to cache hits that avoided process execution.
134+
// - The total count does not include action cache hits, so the sum of the parts is greater than
135+
// the total.
136+
// TODO: Find a better way to report this information, e.g.:
137+
// 15 cache hits (5 action, 5 disk, 5 remote), 10 processes (2 local, 3 remote, 5 sandboxed), 7
138+
// internal.
139+
// A large number of integration tests rely on the current format, though, so changing it is
140+
// non-trivial.
123141
Integer total = spawnSummary.get("total");
124142
if (total == 0) {
125143
return "0 processes.";

0 commit comments

Comments
 (0)