blob: 1034dc98884ef590cb16b3bf57f1d847c54ef4cb [file] [log] [blame]
Nathan Harmata593dc522016-09-28 23:35:46 +00001// Copyright 2016 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.query2;
15
Googler2b503882016-11-28 21:54:43 +000016import com.google.common.annotations.VisibleForTesting;
nharmata398e6dab2018-04-12 15:31:26 -070017import com.google.common.base.Function;
18import com.google.common.base.Predicate;
19import com.google.common.base.Predicates;
nharmata398e6dab2018-04-12 15:31:26 -070020import com.google.common.collect.ImmutableSet;
Nathan Harmata593dc522016-09-28 23:35:46 +000021import com.google.common.collect.Iterables;
nharmata398e6dab2018-04-12 15:31:26 -070022import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
Nathan Harmata593dc522016-09-28 23:35:46 +000023import com.google.devtools.build.lib.packages.Target;
24import com.google.devtools.build.lib.query2.engine.Callback;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000025import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryTaskFuture;
nharmata398e6dab2018-04-12 15:31:26 -070026import com.google.devtools.build.lib.query2.engine.QueryEnvironment.ThreadSafeMutableSet;
Nathan Harmata593dc522016-09-28 23:35:46 +000027import com.google.devtools.build.lib.query2.engine.QueryException;
28import com.google.devtools.build.lib.query2.engine.QueryExpression;
shreyax159a6112018-06-12 15:34:09 -070029import com.google.devtools.build.lib.query2.engine.QueryExpressionContext;
nharmata398e6dab2018-04-12 15:31:26 -070030import com.google.devtools.build.lib.query2.engine.QueryUtil;
31import com.google.devtools.build.lib.query2.engine.QueryUtil.AggregateAllCallback;
Nathan Harmata593dc522016-09-28 23:35:46 +000032import com.google.devtools.build.lib.vfs.PathFragment;
33import com.google.devtools.build.skyframe.SkyKey;
34import java.util.Collection;
nharmata398e6dab2018-04-12 15:31:26 -070035import java.util.Collections;
nharmata2399df02018-04-10 12:30:03 -070036import java.util.Objects;
Nathan Harmata593dc522016-09-28 23:35:46 +000037import java.util.Set;
Googler45b59532018-05-03 11:10:20 -070038import java.util.concurrent.ConcurrentHashMap;
nharmata2399df02018-04-10 12:30:03 -070039import javax.annotation.Nullable;
Nathan Harmata593dc522016-09-28 23:35:46 +000040
Nathan Harmata593dc522016-09-28 23:35:46 +000041/**
42 * Parallel implementations of various functionality in {@link SkyQueryEnvironment}.
43 *
44 * <p>Special attention is given to memory usage. Naive parallel implementations of query
45 * functionality would lead to memory blowup. Instead of dealing with {@link Target}s, we try to
46 * deal with {@link SkyKey}s as much as possible to reduce the number of {@link Package}s forcibly
47 * in memory at any given time.
48 */
49// TODO(bazel-team): Be more deliberate about bounding memory usage here.
nharmata2399df02018-04-10 12:30:03 -070050public class ParallelSkyQueryUtils {
Googler2b503882016-11-28 21:54:43 +000051
52 /** The maximum number of keys to visit at once. */
nharmataa72e31392019-02-19 17:07:10 -080053 @VisibleForTesting public static final int VISIT_BATCH_SIZE = 10000;
Googler2b503882016-11-28 21:54:43 +000054
Nathan Harmata593dc522016-09-28 23:35:46 +000055 private ParallelSkyQueryUtils() {
56 }
57
Nathan Harmata7a5a2362017-03-08 22:42:01 +000058 static QueryTaskFuture<Void> getAllRdepsUnboundedParallel(
Nathan Harmata593dc522016-09-28 23:35:46 +000059 SkyQueryEnvironment env,
60 QueryExpression expression,
shreyax159a6112018-06-12 15:34:09 -070061 QueryExpressionContext<Target> context,
shreyax76e4e422019-06-13 12:15:45 -070062 Callback<Target> callback) {
Nathan Harmata7a5a2362017-03-08 22:42:01 +000063 return env.eval(
Nathan Harmata593dc522016-09-28 23:35:46 +000064 expression,
65 context,
adgarec7084d2019-08-06 17:02:41 -070066 ParallelVisitorUtils.createParallelVisitorCallback(
nharmata398e6dab2018-04-12 15:31:26 -070067 new RdepsUnboundedVisitor.Factory(
shreyax76e4e422019-06-13 12:15:45 -070068 env, /*unfilteredUniverse=*/ Predicates.alwaysTrue(), callback)));
nharmata398e6dab2018-04-12 15:31:26 -070069 }
70
71 static QueryTaskFuture<Void> getAllRdepsBoundedParallel(
72 SkyQueryEnvironment env,
73 QueryExpression expression,
74 int depth,
shreyax159a6112018-06-12 15:34:09 -070075 QueryExpressionContext<Target> context,
shreyax76e4e422019-06-13 12:15:45 -070076 Callback<Target> callback) {
nharmata398e6dab2018-04-12 15:31:26 -070077 return env.eval(
78 expression,
79 context,
adgarec7084d2019-08-06 17:02:41 -070080 ParallelVisitorUtils.createParallelVisitorCallback(
nharmata398e6dab2018-04-12 15:31:26 -070081 new RdepsBoundedVisitor.Factory(
shreyax76e4e422019-06-13 12:15:45 -070082 env, depth, /*universe=*/ Predicates.alwaysTrue(), callback)));
nharmata398e6dab2018-04-12 15:31:26 -070083 }
84
85 static QueryTaskFuture<Void> getRdepsInUniverseUnboundedParallel(
86 SkyQueryEnvironment env,
87 QueryExpression expression,
nharmatab6bf51d2018-07-27 13:49:45 -070088 Predicate<SkyKey> unfilteredUniverse,
shreyax159a6112018-06-12 15:34:09 -070089 QueryExpressionContext<Target> context,
shreyax76e4e422019-06-13 12:15:45 -070090 Callback<Target> callback) {
nharmata398e6dab2018-04-12 15:31:26 -070091 return env.eval(
92 expression,
93 context,
adgarec7084d2019-08-06 17:02:41 -070094 ParallelVisitorUtils.createParallelVisitorCallback(
shreyax76e4e422019-06-13 12:15:45 -070095 new RdepsUnboundedVisitor.Factory(env, unfilteredUniverse, callback)));
nharmata398e6dab2018-04-12 15:31:26 -070096 }
97
98 static QueryTaskFuture<Predicate<SkyKey>> getDTCSkyKeyPredicateFuture(
99 SkyQueryEnvironment env,
100 QueryExpression expression,
shreyax159a6112018-06-12 15:34:09 -0700101 QueryExpressionContext<Target> context,
nharmata398e6dab2018-04-12 15:31:26 -0700102 int processResultsBatchSize,
103 int concurrencyLevel) {
104 QueryTaskFuture<ThreadSafeMutableSet<Target>> universeValueFuture =
105 QueryUtil.evalAll(env, context, expression);
106
107 Function<ThreadSafeMutableSet<Target>, QueryTaskFuture<Predicate<SkyKey>>>
108 getTransitiveClosureAsyncFunction =
nharmata2ef8de62019-04-23 18:30:55 -0700109 universeValue -> {
110 ThreadSafeAggregateAllSkyKeysCallback aggregateAllCallback =
111 new ThreadSafeAggregateAllSkyKeysCallback(concurrencyLevel);
112 return env.execute(
113 () -> {
shreyax6bebe382019-11-13 06:26:26 -0800114 UnfilteredSkyKeyLabelDTCVisitor visitor =
115 new UnfilteredSkyKeyLabelDTCVisitor.Factory(
nharmata2ef8de62019-04-23 18:30:55 -0700116 env,
117 env.createSkyKeyUniquifier(),
118 processResultsBatchSize,
adgarec7084d2019-08-06 17:02:41 -0700119 aggregateAllCallback)
120 .create();
121 visitor.visitAndWaitForCompletion(
shreyax55bc5212020-01-27 11:46:39 -0800122 SkyQueryEnvironment.makeLabelsStrict(universeValue));
nharmata2ef8de62019-04-23 18:30:55 -0700123 return Predicates.in(aggregateAllCallback.getResult());
124 });
125 };
nharmata398e6dab2018-04-12 15:31:26 -0700126
127 return env.transformAsync(universeValueFuture, getTransitiveClosureAsyncFunction);
128 }
129
130 static QueryTaskFuture<Void> getRdepsInUniverseBoundedParallel(
131 SkyQueryEnvironment env,
132 QueryExpression expression,
133 int depth,
134 Predicate<SkyKey> universe,
shreyax159a6112018-06-12 15:34:09 -0700135 QueryExpressionContext<Target> context,
shreyax76e4e422019-06-13 12:15:45 -0700136 Callback<Target> callback) {
nharmata398e6dab2018-04-12 15:31:26 -0700137 return env.eval(
138 expression,
139 context,
adgarec7084d2019-08-06 17:02:41 -0700140 ParallelVisitorUtils.createParallelVisitorCallback(
shreyax76e4e422019-06-13 12:15:45 -0700141 new RdepsBoundedVisitor.Factory(env, depth, universe, callback)));
Nathan Harmata593dc522016-09-28 23:35:46 +0000142 }
143
144 /** Specialized parallel variant of {@link SkyQueryEnvironment#getRBuildFiles}. */
145 static void getRBuildFilesParallel(
146 SkyQueryEnvironment env,
147 Collection<PathFragment> fileIdentifiers,
nharmata20efb2a2018-09-28 12:54:12 -0700148 QueryExpressionContext<Target> context,
nharmata1bd4aaf2017-10-31 11:23:04 -0400149 Callback<Target> callback) throws QueryException, InterruptedException {
Nathan Harmata41b54172016-11-10 18:54:09 +0000150 RBuildFilesVisitor visitor =
Googlerb39486c2019-01-03 08:58:16 -0800151 new RBuildFilesVisitor(
152 env,
nharmataa72e31392019-02-19 17:07:10 -0800153 /*visitUniquifier=*/ env.createSkyKeyUniquifier(),
154 /*resultUniquifier=*/ env.createSkyKeyUniquifier(),
Googlerb39486c2019-01-03 08:58:16 -0800155 context,
shreyaxd8dde882019-02-19 19:40:04 -0800156 callback);
shreyaxd73f7d72020-02-20 13:20:24 -0800157 visitor.visitFileIdentifiersAndWaitForCompletion(env.graph, fileIdentifiers);
Nathan Harmata593dc522016-09-28 23:35:46 +0000158 }
159
shreyax2643d4b2018-05-25 11:12:11 -0700160 static QueryTaskFuture<Void> getDepsUnboundedParallel(
161 SkyQueryEnvironment env,
162 QueryExpression expression,
shreyax159a6112018-06-12 15:34:09 -0700163 QueryExpressionContext<Target> context,
shreyax2643d4b2018-05-25 11:12:11 -0700164 Callback<Target> callback,
shreyax55bc5212020-01-27 11:46:39 -0800165 boolean depsNeedFiltering,
166 QueryExpression caller) {
shreyax2643d4b2018-05-25 11:12:11 -0700167 return env.eval(
168 expression,
169 context,
adgarec7084d2019-08-06 17:02:41 -0700170 ParallelVisitorUtils.createParallelVisitorCallback(
shreyax55bc5212020-01-27 11:46:39 -0800171 new DepsUnboundedVisitor.Factory(env, callback, depsNeedFiltering, context, caller)));
shreyax2643d4b2018-05-25 11:12:11 -0700172 }
173
shreyax19b43772018-05-18 11:45:44 -0700174 static class DepAndRdep {
175 @Nullable final SkyKey dep;
176 final SkyKey rdep;
nharmata2399df02018-04-10 12:30:03 -0700177
shreyax19b43772018-05-18 11:45:44 -0700178 DepAndRdep(@Nullable SkyKey dep, SkyKey rdep) {
nharmata2399df02018-04-10 12:30:03 -0700179 this.dep = dep;
180 this.rdep = rdep;
181 }
182
183 @Override
184 public boolean equals(Object obj) {
185 if (!(obj instanceof DepAndRdep)) {
186 return false;
187 }
188 DepAndRdep other = (DepAndRdep) obj;
189 return Objects.equals(dep, other.dep) && rdep.equals(other.rdep);
190 }
191
192 @Override
193 public int hashCode() {
194 // N.B. - We deliberately use a garbage-free hashCode implementation (rather than e.g.
195 // Objects#hash). Depending on the structure of the graph being traversed, this method can
196 // be very hot.
197 return 31 * Objects.hashCode(dep) + rdep.hashCode();
198 }
199 }
200
shreyax19b43772018-05-18 11:45:44 -0700201 static class DepAndRdepAtDepth {
202 final DepAndRdep depAndRdep;
203 final int rdepDepth;
Nathan Harmata593dc522016-09-28 23:35:46 +0000204
shreyax19b43772018-05-18 11:45:44 -0700205 DepAndRdepAtDepth(DepAndRdep depAndRdep, int rdepDepth) {
nharmata398e6dab2018-04-12 15:31:26 -0700206 this.depAndRdep = depAndRdep;
207 this.rdepDepth = rdepDepth;
208 }
209 }
210
nharmata398e6dab2018-04-12 15:31:26 -0700211 /** Thread-safe {@link AggregateAllCallback} backed by a concurrent {@link Set}. */
212 @ThreadSafe
213 private static class ThreadSafeAggregateAllSkyKeysCallback
214 implements AggregateAllCallback<SkyKey, ImmutableSet<SkyKey>> {
215
216 private final Set<SkyKey> results;
217
218 private ThreadSafeAggregateAllSkyKeysCallback(int concurrencyLevel) {
219 this.results =
Googler45b59532018-05-03 11:10:20 -0700220 Collections.newSetFromMap(
221 new ConcurrentHashMap<>(
222 /*initialCapacity=*/ concurrencyLevel, /*loadFactor=*/ 0.75f));
nharmata398e6dab2018-04-12 15:31:26 -0700223 }
224
225 @Override
226 public void process(Iterable<SkyKey> partialResult)
227 throws QueryException, InterruptedException {
228 Iterables.addAll(results, partialResult);
229 }
230
231 @Override
232 public ImmutableSet<SkyKey> getResult() {
233 return ImmutableSet.copyOf(results);
234 }
235 }
Nathan Harmata593dc522016-09-28 23:35:46 +0000236}