Search in sources :

Example 16 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class BazelConfigurationCollection method createConfigurations.

@Override
@Nullable
public BuildConfiguration createConfigurations(ConfigurationFactory configurationFactory, Cache<String, BuildConfiguration> cache, PackageProviderForConfigurations packageProvider, BuildOptions buildOptions, EventHandler eventHandler) throws InvalidConfigurationException, InterruptedException {
    // Target configuration
    BuildConfiguration targetConfiguration = configurationFactory.getConfiguration(packageProvider, buildOptions, false, cache);
    if (targetConfiguration == null) {
        return null;
    }
    BuildConfiguration dataConfiguration = targetConfiguration;
    // Host configuration
    // Note that this passes in the dataConfiguration, not the target
    // configuration. This is intentional.
    BuildConfiguration hostConfiguration = getHostConfigurationFromRequest(configurationFactory, packageProvider, dataConfiguration, buildOptions, cache);
    if (hostConfiguration == null) {
        return null;
    }
    ListMultimap<SplitTransition<?>, BuildConfiguration> splitTransitionsTable = ArrayListMultimap.create();
    for (SplitTransition<BuildOptions> transition : buildOptions.getPotentialSplitTransitions()) {
        for (BuildOptions splitOptions : transition.split(buildOptions)) {
            BuildConfiguration splitConfig = configurationFactory.getConfiguration(packageProvider, splitOptions, false, cache);
            splitTransitionsTable.put(transition, splitConfig);
        }
    }
    if (packageProvider.valuesMissing()) {
        return null;
    }
    BuildConfiguration result = setupTransitions(targetConfiguration, dataConfiguration, hostConfiguration, splitTransitionsTable);
    result.reportInvalidOptions(eventHandler);
    return result;
}
Also used : BuildConfiguration(com.google.devtools.build.lib.analysis.config.BuildConfiguration) AppleCrosstoolSplitTransition(com.google.devtools.build.lib.rules.objc.AppleCrosstoolSplitTransition) SplitTransition(com.google.devtools.build.lib.packages.Attribute.SplitTransition) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) Nullable(javax.annotation.Nullable)

Example 17 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class RuleContext method getSplitPrerequisites.

/**
   * Returns the a prerequisites keyed by the CPU of their configurations.
   * If the split transition is not active (e.g. split() returned an empty
   * list), the key is an empty Optional.
   */
public Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> getSplitPrerequisites(String attributeName) {
    checkAttribute(attributeName, Mode.SPLIT);
    Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
    // Attribute.java doesn't have the BuildOptions symbol.
    @SuppressWarnings("unchecked") SplitTransition<BuildOptions> transition = (SplitTransition<BuildOptions>) attributeDefinition.getSplitTransition(rule);
    List<ConfiguredTarget> deps = targetMap.get(attributeName);
    List<BuildOptions> splitOptions = transition.split(getConfiguration().getOptions());
    if (splitOptions.isEmpty()) {
        // The split transition is not active. Defer the decision on which CPU to use.
        return ImmutableMap.of(Optional.<String>absent(), deps);
    }
    Set<String> cpus = new HashSet<>();
    for (BuildOptions options : splitOptions) {
        // This method should only be called when the split config is enabled on the command line, in
        // which case this cpu can't be null.
        cpus.add(options.get(BuildConfiguration.Options.class).cpu);
    }
    // Use an ImmutableListMultimap.Builder here to preserve ordering.
    ImmutableListMultimap.Builder<Optional<String>, TransitiveInfoCollection> result = ImmutableListMultimap.builder();
    for (TransitiveInfoCollection t : deps) {
        if (t.getConfiguration() != null) {
            result.put(Optional.of(t.getConfiguration().getCpu()), t);
        } else {
            // Source files don't have a configuration, so we add them to all architecture entries.
            for (String cpu : cpus) {
                result.put(Optional.of(cpu), t);
            }
        }
    }
    return Multimaps.asMap(result.build());
}
Also used : Optional(com.google.common.base.Optional) Attribute(com.google.devtools.build.lib.packages.Attribute) BuildConfiguration(com.google.devtools.build.lib.analysis.config.BuildConfiguration) SplitTransition(com.google.devtools.build.lib.packages.Attribute.SplitTransition) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 18 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class BuildView method getDirectPrerequisiteDependenciesForTesting.

@VisibleForTesting
public OrderedSetMultimap<Attribute, Dependency> getDirectPrerequisiteDependenciesForTesting(final ExtendedEventHandler eventHandler, final ConfiguredTarget ct, BuildConfigurationCollection configurations) throws EvalException, InvalidConfigurationException, InterruptedException, InconsistentAspectOrderException {
    if (!(ct.getTarget() instanceof Rule)) {
        return OrderedSetMultimap.create();
    }
    class SilentDependencyResolver extends DependencyResolver {

        @Override
        protected void invalidVisibilityReferenceHook(TargetAndConfiguration node, Label label) {
            throw new RuntimeException("bad visibility on " + label + " during testing unexpected");
        }

        @Override
        protected void invalidPackageGroupReferenceHook(TargetAndConfiguration node, Label label) {
            throw new RuntimeException("bad package group on " + label + " during testing unexpected");
        }

        @Override
        protected void missingEdgeHook(Target from, Label to, NoSuchThingException e) {
            throw new RuntimeException("missing dependency from " + from.getLabel() + " to " + to + ": " + e.getMessage(), e);
        }

        @Override
        protected Target getTarget(Target from, Label label, NestedSetBuilder<Label> rootCauses) throws InterruptedException {
            try {
                return skyframeExecutor.getPackageManager().getTarget(eventHandler, label);
            } catch (NoSuchThingException e) {
                throw new IllegalStateException(e);
            }
        }

        @Override
        protected List<BuildConfiguration> getConfigurations(Set<Class<? extends BuildConfiguration.Fragment>> fragments, Iterable<BuildOptions> buildOptions) {
            Preconditions.checkArgument(ct.getConfiguration().fragmentClasses().equals(fragments));
            Dependency asDep = Dependency.withTransitionAndAspects(ct.getLabel(), Attribute.ConfigurationTransition.NONE, AspectCollection.EMPTY);
            ImmutableList.Builder<BuildConfiguration> builder = ImmutableList.builder();
            for (BuildOptions options : buildOptions) {
                builder.add(Iterables.getOnlyElement(skyframeExecutor.getConfigurations(eventHandler, options, ImmutableList.<Dependency>of(asDep)).values()));
            }
            return builder.build();
        }
    }
    DependencyResolver dependencyResolver = new SilentDependencyResolver();
    TargetAndConfiguration ctgNode = new TargetAndConfiguration(ct.getTarget(), ct.getConfiguration());
    return dependencyResolver.dependentNodeMap(ctgNode, configurations.getHostConfiguration(), /*aspect=*/
    null, getConfigurableAttributeKeysForTesting(eventHandler, ctgNode));
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) NestedSet(com.google.devtools.build.lib.collect.nestedset.NestedSet) ImmutableList(com.google.common.collect.ImmutableList) Label(com.google.devtools.build.lib.cmdline.Label) BuildConfiguration(com.google.devtools.build.lib.analysis.config.BuildConfiguration) Target(com.google.devtools.build.lib.packages.Target) NoSuchThingException(com.google.devtools.build.lib.packages.NoSuchThingException) NestedSetBuilder(com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) Rule(com.google.devtools.build.lib.packages.Rule) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 19 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class LipoDataTransition method apply.

@Override
public BuildOptions apply(BuildOptions options) {
    if (options.get(BuildConfiguration.Options.class).isHost) {
        return options;
    }
    // LIPO context to change.
    if (!options.contains(CppOptions.class)) {
        return options;
    }
    CppOptions cppOptions = options.get(CppOptions.class);
    if (cppOptions.lipoMode == CrosstoolConfig.LipoMode.OFF) {
        return options;
    }
    options = options.clone();
    cppOptions = options.get(CppOptions.class);
    // Once autoFdoLipoData is on, it stays on (through all future transitions).
    if (!cppOptions.autoFdoLipoData && cppOptions.fdoOptimize != null) {
        cppOptions.autoFdoLipoData = FdoSupport.isAutoFdo(cppOptions.fdoOptimize);
    }
    cppOptions.lipoMode = CrosstoolConfig.LipoMode.OFF;
    cppOptions.fdoInstrument = null;
    cppOptions.fdoOptimize = null;
    return options;
}
Also used : CppOptions(com.google.devtools.build.lib.rules.cpp.CppOptions) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) CppOptions(com.google.devtools.build.lib.rules.cpp.CppOptions)

Example 20 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class ConfiguredTargetFunction method getDynamicConfigurations.

/**
   * Creates a dynamic configuration for each dep that's custom-fitted specifically for that dep.
   *
   * <p>More specifically: given a set of {@link Dependency} instances holding dynamic config
   * transition requests (e.g. {@link Dependency#hasStaticConfiguration()} == false}), returns
   * equivalent dependencies containing dynamically created configurations applying those
   * transitions. If {@link BuildConfiguration.Options#trimConfigurations()} is true, these
   * configurations only contain the fragments needed by the dep and its transitive closure. Else
   * the configurations unconditionally include all fragments.
   *
   * <p>This method is heavily performance-optimized. Because it, in aggregate, reads over every
   * edge in the configured target graph, small inefficiencies can have observable impact on
   * analysis time. Keep this in mind when making modifications and performance-test any changes you
   * make.
   *
   * @param env Skyframe evaluation environment
   * @param ctgValue the label and the configuration of the node
   * @param originalDeps the set of configuration transition requests for this target's attributes
   * @param hostConfiguration the host configuration
   * @param ruleClassProvider the rule class provider for determining the right configuration
   *    fragments to apply to deps
   *
   * @return a mapping from each attribute to the {@link BuildConfiguration}s and {@link Label}s
   *    to use for that attribute's deps. Returns null if not all Skyframe dependencies are
   *    available yet.
   */
@Nullable
static OrderedSetMultimap<Attribute, Dependency> getDynamicConfigurations(Environment env, TargetAndConfiguration ctgValue, OrderedSetMultimap<Attribute, Dependency> originalDeps, BuildConfiguration hostConfiguration, RuleClassProvider ruleClassProvider) throws DependencyEvaluationException, InterruptedException {
    // Maps each Skyframe-evaluated BuildConfiguration to the dependencies that need that
    // configuration. For cases where Skyframe isn't needed to get the configuration (e.g. when
    // we just re-used the original rule's configuration), we should skip this outright.
    Multimap<SkyKey, Map.Entry<Attribute, Dependency>> keysToEntries = LinkedListMultimap.create();
    // Stores the result of applying a dynamic transition to the current configuration using a
    // particular subset of fragments. By caching this, we save from redundantly computing the
    // same transition for every dependency edge that requests that transition. This can have
    // real effect on analysis time for commonly triggered transitions.
    //
    // Split transitions may map to multiple values. All other transitions map to one.
    Map<FragmentsAndTransition, List<BuildOptions>> transitionsMap = new LinkedHashMap<>();
    // The fragments used by the current target's configuration.
    Set<Class<? extends BuildConfiguration.Fragment>> ctgFragments = ctgValue.getConfiguration().fragmentClasses();
    BuildOptions ctgOptions = ctgValue.getConfiguration().getOptions();
    // Stores the dynamically configured versions of each dependency. This method must preserve the
    // original label ordering of each attribute. For example, if originalDeps.get("data") is
    // [":a", ":b"], the dynamic variant must also be [":a", ":b"] in the same order. Because we may
    // not actualize the results in order (some results need Skyframe-evaluated configurations while
    // others can be computed trivially), we dump them all into this map, then as a final step
    // iterate through the original list and pluck out values from here for the final value.
    //
    // For split transitions, originaldeps.get("data") = [":a", ":b"] can produce the output
    // [":a"<config1>, ":a"<config2>, ..., ":b"<config1>, ":b"<config2>, ...]. All instances of ":a"
    // still appear before all instances of ":b". But the [":a"<config1>, ":a"<config2>"] subset may
    // be in any (deterministic) order. In particular, this may not be the same order as
    // SplitTransition.split. If needed, this code can be modified to use that order, but that
    // involves more runtime in performance-critical code, so we won't make that change without a
    // clear need.
    //
    // This map is used heavily by all builds. Inserts and gets should be as fast as possible.
    Multimap<AttributeAndLabel, Dependency> dynamicDeps = LinkedHashMultimap.create();
    // Performance optimization: This method iterates over originalDeps twice. By storing
    // AttributeAndLabel instances in this list, we avoid having to recreate them the second time
    // (particularly avoid recomputing their hash codes). Profiling shows this shaves 25% off this
    // method's execution time (at the time of this comment).
    ArrayList<AttributeAndLabel> attributesAndLabels = new ArrayList<>(originalDeps.size());
    for (Map.Entry<Attribute, Dependency> depsEntry : originalDeps.entries()) {
        Dependency dep = depsEntry.getValue();
        AttributeAndLabel attributeAndLabel = new AttributeAndLabel(depsEntry.getKey(), dep.getLabel());
        attributesAndLabels.add(attributeAndLabel);
        // simple cc_binary show this saves ~1% of total analysis phase time.
        if (dep.hasStaticConfiguration()) {
            continue;
        }
        // Figure out the required fragments for this dep and its transitive closure.
        Set<Class<? extends BuildConfiguration.Fragment>> depFragments = getTransitiveFragments(env, dep.getLabel(), ctgValue.getConfiguration());
        if (depFragments == null) {
            return null;
        }
        // to 0.5% of total analysis time as profiled over a simple cc_binary).
        if (ctgValue.getConfiguration().trimConfigurations()) {
            checkForMissingFragments(env, ctgValue, attributeAndLabel.attribute.getName(), dep, depFragments);
        }
        boolean sameFragments = depFragments.equals(ctgFragments);
        Attribute.Transition transition = dep.getTransition();
        if (sameFragments) {
            if (transition == Attribute.ConfigurationTransition.NONE) {
                // The dep uses the same exact configuration.
                putOnlyEntry(dynamicDeps, attributeAndLabel, Dependency.withConfigurationAndAspects(dep.getLabel(), ctgValue.getConfiguration(), dep.getAspects()));
                continue;
            } else if (transition == HostTransition.INSTANCE) {
                // The current rule's host configuration can also be used for the dep. We short-circuit
                // the standard transition logic for host transitions because these transitions are
                // uniquely frequent. It's possible, e.g., for every node in the configured target graph
                // to incur multiple host transitions. So we aggressively optimize to avoid hurting
                // analysis time.
                putOnlyEntry(dynamicDeps, attributeAndLabel, Dependency.withConfigurationAndAspects(dep.getLabel(), hostConfiguration, dep.getAspects()));
                continue;
            }
        }
        // Apply the transition or use the cached result if it was already applied.
        FragmentsAndTransition transitionKey = new FragmentsAndTransition(depFragments, transition);
        List<BuildOptions> toOptions = transitionsMap.get(transitionKey);
        if (toOptions == null) {
            toOptions = getDynamicTransitionOptions(ctgOptions, transition, depFragments, ruleClassProvider, !sameFragments);
            transitionsMap.put(transitionKey, toOptions);
        }
        // configuration.
        if (sameFragments && toOptions.size() == 1 && Iterables.getOnlyElement(toOptions).equals(ctgOptions)) {
            putOnlyEntry(dynamicDeps, attributeAndLabel, Dependency.withConfigurationAndAspects(dep.getLabel(), ctgValue.getConfiguration(), dep.getAspects()));
            continue;
        }
        // If we get here, we have to get the configuration from Skyframe.
        for (BuildOptions options : toOptions) {
            keysToEntries.put(BuildConfigurationValue.key(depFragments, options), depsEntry);
        }
    }
    // Get all BuildConfigurations we need from Skyframe. While not every value might be available,
    // we don't call env.valuesMissing() here because that could be true from the earlier
    // resolver.dependentNodeMap call in computeDependencies, which also calls Skyframe. This method
    // doesn't need those missing values, but it still has to be called after
    // resolver.dependentNodeMap because it consumes that method's output. The reason the missing
    // values don't matter is because resolver.dependentNodeMap still returns "partial" results
    // and this method runs over whatever's available.
    //
    // While there would be no *correctness* harm in nulling out early, there's significant
    // *performance* harm. Profiling shows that putting "if (env.valuesMissing()) { return null; }"
    // here (or even after resolver.dependentNodeMap) produces a ~30% performance hit on the
    // analysis phase. That's because resolveConfiguredTargetDependencies and
    // resolveAspectDependencies don't get a chance to make their own Skyframe requests before
    // bailing out of this ConfiguredTargetFunction call. Ideally we could batch all requests
    // from all methods into a single Skyframe call, but there are enough subtle data flow
    // dependencies in ConfiguredTargetFucntion to make that impractical.
    Map<SkyKey, ValueOrException<InvalidConfigurationException>> depConfigValues = env.getValuesOrThrow(keysToEntries.keySet(), InvalidConfigurationException.class);
    // Now fill in the remaining unresolved deps with the now-resolved configurations.
    try {
        for (Map.Entry<SkyKey, ValueOrException<InvalidConfigurationException>> entry : depConfigValues.entrySet()) {
            SkyKey key = entry.getKey();
            ValueOrException<InvalidConfigurationException> valueOrException = entry.getValue();
            if (valueOrException.get() == null) {
                // null out on missing values from *this specific Skyframe request*.
                return null;
            }
            BuildConfigurationValue trimmedConfig = (BuildConfigurationValue) valueOrException.get();
            for (Map.Entry<Attribute, Dependency> info : keysToEntries.get(key)) {
                Dependency originalDep = info.getValue();
                AttributeAndLabel attr = new AttributeAndLabel(info.getKey(), originalDep.getLabel());
                Dependency resolvedDep = Dependency.withConfigurationAndAspects(originalDep.getLabel(), trimmedConfig.getConfiguration(), originalDep.getAspects());
                if (attr.attribute.hasSplitConfigurationTransition()) {
                    dynamicDeps.put(attr, resolvedDep);
                } else {
                    putOnlyEntry(dynamicDeps, attr, resolvedDep);
                }
            }
        }
    } catch (InvalidConfigurationException e) {
        throw new DependencyEvaluationException(e);
    }
    return sortDynamicallyConfiguredDeps(originalDeps, dynamicDeps, attributesAndLabels);
}
Also used : Attribute(com.google.devtools.build.lib.packages.Attribute) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) InvalidConfigurationException(com.google.devtools.build.lib.analysis.config.InvalidConfigurationException) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) SkyKey(com.google.devtools.build.skyframe.SkyKey) Dependency(com.google.devtools.build.lib.analysis.Dependency) ValueOrException(com.google.devtools.build.skyframe.ValueOrException) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Nullable(javax.annotation.Nullable)

Aggregations

BuildOptions (com.google.devtools.build.lib.analysis.config.BuildOptions)23 BuildConfiguration (com.google.devtools.build.lib.analysis.config.BuildConfiguration)12 ImmutableList (com.google.common.collect.ImmutableList)6 InvalidConfigurationException (com.google.devtools.build.lib.analysis.config.InvalidConfigurationException)4 SkyKey (com.google.devtools.build.skyframe.SkyKey)4 ArrayList (java.util.ArrayList)4 Dependency (com.google.devtools.build.lib.analysis.Dependency)3 Label (com.google.devtools.build.lib.cmdline.Label)3 Attribute (com.google.devtools.build.lib.packages.Attribute)3 HashSet (java.util.HashSet)3 ImmutableMap (com.google.common.collect.ImmutableMap)2 ImmutableSet (com.google.common.collect.ImmutableSet)2 Options (com.google.devtools.build.lib.analysis.config.BuildConfiguration.Options)2 BuildConfigurationCollection (com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection)2 PatchTransition (com.google.devtools.build.lib.analysis.config.PatchTransition)2 InvocationPolicyEnforcer (com.google.devtools.build.lib.flags.InvocationPolicyEnforcer)2 SplitTransition (com.google.devtools.build.lib.packages.Attribute.SplitTransition)2 LoadingResult (com.google.devtools.build.lib.pkgcache.LoadingResult)2 PackageCacheOptions (com.google.devtools.build.lib.pkgcache.PackageCacheOptions)2 ValueOrException (com.google.devtools.build.skyframe.ValueOrException)2