Parallelize target pattern preloading (used by 'blaze query').
RELNOTES: None
PiperOrigin-RevId: 165973661
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
index c84e849..e33c85e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
@@ -14,8 +14,8 @@
package com.google.devtools.build.lib.skyframe;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.ResolvedTargets;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
@@ -55,7 +55,8 @@
FilteringPolicy policy,
boolean keepGoing)
throws TargetParsingException, InterruptedException {
- return parseTargetPatternList(offset, eventHandler, targetPatterns, policy, keepGoing);
+ return parseTargetPatternList(
+ offset, eventHandler, ImmutableList.copyOf(targetPatterns), policy, keepGoing);
}
@Override
@@ -82,29 +83,40 @@
throws TargetParsingException, InterruptedException {
// TODO(bazel-team): This is used only in "blaze query". There are plans to dramatically change
// how query works on Skyframe, in which case this method is likely to go away.
- // We cannot use an ImmutableMap here because there may be null values.
- Map<String, ResolvedTargets<Target>> result = Maps.newHashMapWithExpectedSize(patterns.size());
+ ImmutableList.Builder<TargetPatternsAndKeysAndResultBuilder>
+ targetPatternsAndKeysAndResultListBuilder = ImmutableList.builder();
+ FilteringPolicy policy = DEFAULT_FILTERING_POLICY;
for (String pattern : patterns) {
- // TODO(bazel-team): This could be parallelized to improve performance. [skyframe-loading]
- result.put(pattern, parseTargetPattern(eventHandler, pattern, keepGoing));
+ ImmutableList<String> singletonPatternList = ImmutableList.of(pattern);
+ targetPatternsAndKeysAndResultListBuilder.add(new TargetPatternsAndKeysAndResultBuilder(
+ singletonPatternList,
+ getTargetPatternKeys(
+ offset, eventHandler, singletonPatternList, policy, keepGoing),
+ createTargetPatternEvaluatorUtil(policy, eventHandler, keepGoing)));
+
}
- return result;
+ ImmutableList<ResolvedTargets<Target>> batchResult = parseTargetPatternKeysBatch(
+ targetPatternsAndKeysAndResultListBuilder.build(),
+ SkyframeExecutor.DEFAULT_THREAD_COUNT,
+ keepGoing,
+ eventHandler);
+ Preconditions.checkState(patterns.size() == batchResult.size(), patterns);
+ ImmutableMap.Builder<String, ResolvedTargets<Target>> resultBuilder = ImmutableMap.builder();
+ int i = 0;
+ for (String pattern : patterns) {
+ resultBuilder.put(pattern, batchResult.get(i++));
+ }
+ return resultBuilder.build();
}
- /**
- * Loads a list of target patterns (eg, "foo/..."). When policy is set to FILTER_TESTS,
- * test_suites are going to be expanded.
- */
- ResolvedTargets<Target> parseTargetPatternList(
+ private Iterable<TargetPatternKey> getTargetPatternKeys(
String offset,
ExtendedEventHandler eventHandler,
- List<String> targetPatterns,
+ ImmutableList<String> targetPatterns,
FilteringPolicy policy,
- boolean keepGoing)
- throws InterruptedException, TargetParsingException {
+ boolean keepGoing) throws TargetParsingException {
Iterable<TargetPatternSkyKeyOrException> keysMaybe =
TargetPatternValue.keys(targetPatterns, policy, offset);
-
ImmutableList.Builder<TargetPatternKey> builder = ImmutableList.builder();
for (TargetPatternSkyKeyOrException skyKeyOrException : keysMaybe) {
try {
@@ -122,14 +134,30 @@
eventHandler.handle(Event.error("Skipping '" + pattern + "': " + e.getMessage()));
}
}
- ImmutableList<TargetPatternKey> skyKeys = builder.build();
- return parseTargetPatternKeys(
- targetPatterns,
- skyKeys,
- SkyframeExecutor.DEFAULT_THREAD_COUNT,
- keepGoing,
- eventHandler,
- createTargetPatternEvaluatorUtil(policy, eventHandler, keepGoing));
+ return builder.build();
+ }
+
+ /**
+ * Loads a list of target patterns (eg, "foo/..."). When policy is set to FILTER_TESTS,
+ * test_suites are going to be expanded.
+ */
+ private ResolvedTargets<Target> parseTargetPatternList(
+ String offset,
+ ExtendedEventHandler eventHandler,
+ ImmutableList<String> targetPatterns,
+ FilteringPolicy policy,
+ boolean keepGoing)
+ throws InterruptedException, TargetParsingException {
+ return Iterables.getOnlyElement(
+ parseTargetPatternKeysBatch(
+ ImmutableList.of(
+ new TargetPatternsAndKeysAndResultBuilder(
+ targetPatterns,
+ getTargetPatternKeys(offset, eventHandler, targetPatterns, policy, keepGoing),
+ createTargetPatternEvaluatorUtil(policy, eventHandler, keepGoing))),
+ SkyframeExecutor.DEFAULT_THREAD_COUNT,
+ keepGoing,
+ eventHandler));
}
private TargetPatternsResultBuilder createTargetPatternEvaluatorUtil(
@@ -140,65 +168,95 @@
: new BuildTargetPatternsResultBuilder();
}
- private ResolvedTargets<Target> parseTargetPatternKeys(
- List<String> targetPattern,
- Iterable<TargetPatternKey> patternSkyKeys,
+ private class TargetPatternsAndKeysAndResultBuilder {
+ private final ImmutableList<String> targetPatterns;
+ private final Iterable<TargetPatternKey> patternSkyKeys;
+ private final TargetPatternsResultBuilder resultBuilder;
+
+ private TargetPatternsAndKeysAndResultBuilder(
+ ImmutableList<String> targetPatterns,
+ Iterable<TargetPatternKey> patternSkyKeys,
+ TargetPatternsResultBuilder resultBuilder) {
+ this.targetPatterns = targetPatterns;
+ this.patternSkyKeys = patternSkyKeys;
+ this.resultBuilder = resultBuilder;
+ }
+ }
+
+ private ImmutableList<ResolvedTargets<Target>> parseTargetPatternKeysBatch(
+ ImmutableList<TargetPatternsAndKeysAndResultBuilder> targetPatternsAndKeysAndResultBuilders,
int numThreads,
boolean keepGoing,
- ExtendedEventHandler eventHandler,
- TargetPatternsResultBuilder finalTargetSetEvaluator)
+ ExtendedEventHandler eventHandler)
throws InterruptedException, TargetParsingException {
- EvaluationResult<TargetPatternValue> result =
- skyframeExecutor.targetPatterns(patternSkyKeys, numThreads, keepGoing, eventHandler);
-
- String errorMessage = null;
- for (TargetPatternKey key : patternSkyKeys) {
- TargetPatternValue resultValue = result.get(key);
- if (resultValue != null) {
- ResolvedTargets<Label> results = resultValue.getTargets();
- if (key.isNegative()) {
- finalTargetSetEvaluator.addLabelsOfNegativePattern(results);
- } else {
- finalTargetSetEvaluator.addLabelsOfPositivePattern(results);
- }
- } else {
- String rawPattern = key.getPattern();
- ErrorInfo error = result.errorMap().get(key);
- if (error == null) {
- Preconditions.checkState(!keepGoing);
- continue;
- }
- if (error.getException() != null) {
- // This exception may not be a TargetParsingException because in a nokeep_going build, the
- // target pattern parser may swallow a NoSuchPackageException but the framework will
- // bubble it up anyway.
- Preconditions.checkArgument(!keepGoing
- || error.getException() instanceof TargetParsingException, error);
- errorMessage = error.getException().getMessage();
- } else if (!Iterables.isEmpty(error.getCycleInfo())) {
- errorMessage = "cycles detected during target parsing";
- skyframeExecutor.getCyclesReporter().reportCycles(
- error.getCycleInfo(), key, eventHandler);
- } else {
- throw new IllegalStateException(error.toString());
- }
- if (keepGoing) {
- eventHandler.handle(Event.error("Skipping '" + rawPattern + "': " + errorMessage));
- eventHandler.post(PatternExpandingError.skipped(rawPattern, errorMessage));
- }
- finalTargetSetEvaluator.setError();
- }
+ ImmutableList.Builder<TargetPatternKey> allKeysBuilder = ImmutableList.builder();
+ for (TargetPatternsAndKeysAndResultBuilder targetPatternsAndKeysAndResultBuilder
+ : targetPatternsAndKeysAndResultBuilders) {
+ allKeysBuilder.addAll(targetPatternsAndKeysAndResultBuilder.patternSkyKeys);
}
-
- if (result.hasError()) {
- Preconditions.checkState(errorMessage != null, "unexpected errors: %s", result.errorMap());
- finalTargetSetEvaluator.setError();
- if (!keepGoing) {
- eventHandler.post(PatternExpandingError.failed(targetPattern, errorMessage));
- throw new TargetParsingException(errorMessage);
- }
- }
+ EvaluationResult<TargetPatternValue> result = skyframeExecutor.targetPatterns(
+ allKeysBuilder.build(), numThreads, keepGoing, eventHandler);
WalkableGraph walkableGraph = Preconditions.checkNotNull(result.getWalkableGraph(), result);
- return finalTargetSetEvaluator.build(walkableGraph);
+ ImmutableList.Builder<ResolvedTargets<Target>> resolvedTargetsListBuilder =
+ ImmutableList.builder();
+ for (TargetPatternsAndKeysAndResultBuilder targetPatternsAndKeysAndResultBuilder
+ : targetPatternsAndKeysAndResultBuilders) {
+ ImmutableList<String> targetPatterns = targetPatternsAndKeysAndResultBuilder.targetPatterns;
+ Iterable<TargetPatternKey> patternSkyKeys =
+ targetPatternsAndKeysAndResultBuilder.patternSkyKeys;
+ TargetPatternsResultBuilder resultBuilder =
+ targetPatternsAndKeysAndResultBuilder.resultBuilder;
+ String errorMessage = null;
+ boolean hasError = false;
+ for (TargetPatternKey key : patternSkyKeys) {
+ TargetPatternValue resultValue = result.get(key);
+ if (resultValue != null) {
+ ResolvedTargets<Label> results = resultValue.getTargets();
+ if (key.isNegative()) {
+ resultBuilder.addLabelsOfNegativePattern(results);
+ } else {
+ resultBuilder.addLabelsOfPositivePattern(results);
+ }
+ } else {
+ String rawPattern = key.getPattern();
+ ErrorInfo error = result.errorMap().get(key);
+ if (error == null) {
+ Preconditions.checkState(!keepGoing);
+ continue;
+ }
+ hasError = true;
+ if (error.getException() != null) {
+ // This exception may not be a TargetParsingException because in a nokeep_going build,
+ // the target pattern parser may swallow a NoSuchPackageException but the framework will
+ // bubble it up anyway.
+ Preconditions.checkArgument(!keepGoing
+ || error.getException() instanceof TargetParsingException, error);
+ errorMessage = error.getException().getMessage();
+ } else if (!Iterables.isEmpty(error.getCycleInfo())) {
+ errorMessage = "cycles detected during target parsing";
+ skyframeExecutor.getCyclesReporter().reportCycles(
+ error.getCycleInfo(), key, eventHandler);
+ } else {
+ throw new IllegalStateException(error.toString());
+ }
+ if (keepGoing) {
+ eventHandler.handle(Event.error("Skipping '" + rawPattern + "': " + errorMessage));
+ eventHandler.post(PatternExpandingError.skipped(rawPattern, errorMessage));
+ }
+ resultBuilder.setError();
+ }
+ }
+
+ if (hasError) {
+ Preconditions.checkState(errorMessage != null, "unexpected errors: %s", result.errorMap());
+ resultBuilder.setError();
+ if (!keepGoing) {
+ eventHandler.post(PatternExpandingError.failed(targetPatterns, errorMessage));
+ throw new TargetParsingException(errorMessage);
+ }
+ }
+ resolvedTargetsListBuilder.add(resultBuilder.build(walkableGraph));
+ }
+ return resolvedTargetsListBuilder.build();
}
}