aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis
diff options
context:
space:
mode:
authorGravatar mjhalupka <mjhalupka@google.com>2018-07-11 11:09:46 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-07-11 11:11:12 -0700
commitb6385d1e8f17fa5b1bdcd08c3577634901d4b4b5 (patch)
tree8d20b4e7026d0b494d9ebdcf651343f14bcc113b /src/main/java/com/google/devtools/build/lib/analysis
parente0a68ab35294b0acff1226d74744957780967ae4 (diff)
Move caching to BuildOptions instead of BuildConfigurationValue.Key.
PiperOrigin-RevId: 204154609
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java139
1 files changed, 138 insertions, 1 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
index cc31da8a31..603d2df6c4 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
@@ -27,6 +27,10 @@ import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
+import com.google.devtools.build.lib.skyframe.serialization.DeserializationContext;
+import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
+import com.google.devtools.build.lib.skyframe.serialization.SerializationContext;
+import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.util.OrderedSetMultimap;
@@ -36,6 +40,10 @@ import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsClassProvider;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.CodedOutputStream;
+import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -50,6 +58,8 @@ import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -60,6 +70,7 @@ import javax.annotation.Nullable;
public final class BuildOptions implements Cloneable, Serializable {
private static final Comparator<Class<? extends FragmentOptions>>
lexicalFragmentOptionsComparator = Comparator.comparing(Class::getName);
+ private static final Logger logger = Logger.getLogger(BuildOptions.class.getName());
/**
* Creates a BuildOptions object with all options set to their default values, processed by the
@@ -544,7 +555,6 @@ public final class BuildOptions implements Cloneable, Serializable {
* another: the full fragments of the second one, the fragment classes of the first that should be
* omitted, and the values of any fields that should be changed.
*/
- @AutoCodec
public static class OptionsDiffForReconstruction {
private final Map<Class<? extends FragmentOptions>, Map<String, Object>> differingOptions;
private final ImmutableSet<Class<? extends FragmentOptions>> extraFirstFragmentClasses;
@@ -627,5 +637,132 @@ public final class BuildOptions implements Cloneable, Serializable {
public int hashCode() {
return 31 * Arrays.hashCode(baseFingerprint) + checksum.hashCode();
}
+
+ private static class Codec implements ObjectCodec<OptionsDiffForReconstruction> {
+
+ @Override
+ public Class<OptionsDiffForReconstruction> getEncodedClass() {
+ return OptionsDiffForReconstruction.class;
+ }
+
+ @Override
+ public void serialize(
+ SerializationContext context,
+ OptionsDiffForReconstruction diff,
+ CodedOutputStream codedOut)
+ throws SerializationException, IOException {
+ OptionsDiffCache cache = context.getDependency(OptionsDiffCache.class);
+ ByteString bytes = cache.getBytesFromOptionsDiff(diff);
+ if (bytes == null) {
+ context = context.getNewNonMemoizingContext();
+ ByteString.Output byteStringOut = ByteString.newOutput();
+ CodedOutputStream bytesOut = CodedOutputStream.newInstance(byteStringOut);
+ context.serialize(diff.differingOptions, bytesOut);
+ context.serialize(diff.extraFirstFragmentClasses, bytesOut);
+ context.serialize(diff.extraSecondFragments, bytesOut);
+ bytesOut.writeInt32NoTag(diff.baseFingerprint.length);
+ bytesOut.writeByteArrayNoTag(diff.baseFingerprint);
+ context.serialize(diff.checksum, bytesOut);
+ bytesOut.flush();
+ byteStringOut.flush();
+ int optionsDiffSize = byteStringOut.size();
+ bytes = byteStringOut.toByteString();
+ cache.putBytesFromOptionsDiff(diff, bytes);
+ logger.info(
+ "Serialized OptionsDiffForReconstruction "
+ + diff.toString()
+ + ". Diff took "
+ + optionsDiffSize
+ + " bytes.");
+ }
+ codedOut.writeBytesNoTag(bytes);
+ }
+
+ @Override
+ public OptionsDiffForReconstruction deserialize(
+ DeserializationContext context, CodedInputStream codedIn)
+ throws SerializationException, IOException {
+ OptionsDiffCache cache = context.getDependency(OptionsDiffCache.class);
+ ByteString bytes = codedIn.readBytes();
+ OptionsDiffForReconstruction diff = cache.getOptionsDiffFromBytes(bytes);
+ if (diff == null) {
+ CodedInputStream codedInput = bytes.newCodedInput();
+ context = context.getNewNonMemoizingContext();
+ Map<Class<? extends FragmentOptions>, Map<String, Object>> differingOptions =
+ context.deserialize(codedInput);
+ ImmutableSet<Class<? extends FragmentOptions>> extraFirstFragmentClasses =
+ context.deserialize(codedInput);
+ ImmutableList<FragmentOptions> extraSecondFragments = context.deserialize(codedInput);
+ int fingerprintLength = codedInput.readInt32();
+ byte[] baseFingerprint = codedInput.readRawBytes(fingerprintLength);
+ String checksum = context.deserialize(codedInput);
+ diff =
+ new OptionsDiffForReconstruction(
+ differingOptions,
+ extraFirstFragmentClasses,
+ extraSecondFragments,
+ baseFingerprint,
+ checksum);
+ cache.putOptionsDiffFromBytes(bytes, diff);
+ }
+ return diff;
+ }
+ }
+ }
+
+ /**
+ * Injected cache for {@code Codec}, so that we don't have to repeatedly serialize the same
+ * object. We still incur the over-the-wire cost of the bytes, but we don't use CPU to repeatedly
+ * compute it.
+ *
+ * <p>We provide the cache as an injected dependency so that different serializers' caches are
+ * isolated.
+ */
+ public interface OptionsDiffCache {
+ ByteString getBytesFromOptionsDiff(OptionsDiffForReconstruction diff);
+
+ void putBytesFromOptionsDiff(OptionsDiffForReconstruction diff, ByteString bytes);
+
+ OptionsDiffForReconstruction getOptionsDiffFromBytes(ByteString bytes);
+
+ void putOptionsDiffFromBytes(ByteString bytes, OptionsDiffForReconstruction diff);
+ }
+
+ /**
+ * Implementation of the {@link OptionsDiffCache} that acts as a {@code BiMap} utilizing two
+ * {@code ConcurrentHashMaps}.
+ */
+ public static class DiffToByteCache implements OptionsDiffCache {
+ // We expect there to be very few elements so keeping the reverse map as well as the forward
+ // map should be very cheap.
+ private static final ConcurrentHashMap<OptionsDiffForReconstruction, ByteString>
+ diffToByteStringMap = new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap<ByteString, OptionsDiffForReconstruction>
+ byteStringToDiffMap = new ConcurrentHashMap<>();
+
+ @VisibleForTesting
+ public DiffToByteCache() {}
+
+ @Override
+ public ByteString getBytesFromOptionsDiff(OptionsDiffForReconstruction diff) {
+ return diffToByteStringMap.get(diff);
+ }
+
+ @Override
+ public void putBytesFromOptionsDiff(OptionsDiffForReconstruction diff, ByteString bytes) {
+ diffToByteStringMap.put(diff, bytes);
+ byteStringToDiffMap.put(bytes, diff);
+ }
+
+ @Override
+ public OptionsDiffForReconstruction getOptionsDiffFromBytes(ByteString bytes) {
+ return byteStringToDiffMap.get(bytes);
+ }
+
+ @Override
+ public void putOptionsDiffFromBytes(ByteString bytes, OptionsDiffForReconstruction diff) {
+ diffToByteStringMap.put(diff, bytes);
+ byteStringToDiffMap.put(bytes, diff);
+ }
}
}