// Copyright 2018 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.skyframe; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.actions.ActionExecutionMetadata; import com.google.devtools.build.lib.actions.ActionKeyContext; import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.AnalysisProtos; import com.google.devtools.build.lib.analysis.AnalysisProtos.ActionGraphContainer; import com.google.devtools.build.lib.analysis.AnalysisProtos.Configuration; import com.google.devtools.build.lib.analysis.AnalysisProtos.DepSetOfFiles; import com.google.devtools.build.lib.analysis.AnalysisProtos.KeyValuePair; import com.google.devtools.build.lib.analysis.AnalysisProtos.RuleClass; import com.google.devtools.build.lib.analysis.AnalysisProtos.Target; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.NestedSetView; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.AspectDescriptor; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * Encapsulates necessary functionality to dump the current skyframe state of the action graph to * proto format. */ public class ActionGraphDump { private final Map knownArtifacts = new HashMap<>(); private final Map knownConfigurations = new HashMap<>(); private final Map knownTargets = new HashMap<>(); private final Map knownAspectDescriptors = new HashMap<>(); private final Map knownRuleClassStrings = new HashMap<>(); // The NestedSet is identified by their raw 'children' object since multiple NestedSetViews // can point to the same object. private final Map knownNestedSets = new HashMap<>(); private final ActionGraphContainer.Builder actionGraphBuilder = ActionGraphContainer.newBuilder(); private final ActionKeyContext actionKeyContext = new ActionKeyContext(); private final Set actionGraphTargets; public ActionGraphDump(List actionGraphTargets) { this.actionGraphTargets = ImmutableSet.copyOf(actionGraphTargets); } public ActionKeyContext getActionKeyContext() { return actionKeyContext; } private boolean includeInActionGraph(String labelString) { if (actionGraphTargets.size() == 1 && Iterables.getOnlyElement(actionGraphTargets).equals("...")) { return true; } return actionGraphTargets.contains(labelString); } private String ruleClassStringToId(String ruleClassString) { if (!knownRuleClassStrings.containsKey(ruleClassString)) { String targetId = String.valueOf(knownRuleClassStrings.size()); knownRuleClassStrings.put(ruleClassString, targetId); RuleClass.Builder ruleClassBuilder = RuleClass.newBuilder().setId(targetId).setName(ruleClassString); actionGraphBuilder.addRuleClasses(ruleClassBuilder.build()); } return knownRuleClassStrings.get(ruleClassString); } private String targetToId(Label label, String ruleClassString) { if (!knownTargets.containsKey(label)) { String targetId = String.valueOf(knownTargets.size()); knownTargets.put(label, targetId); Target.Builder targetBuilder = Target.newBuilder(); targetBuilder.setId(targetId).setLabel(label.toString()); if (ruleClassString != null) { targetBuilder.setRuleClassId(ruleClassStringToId(ruleClassString)); } actionGraphBuilder.addTargets(targetBuilder.build()); } return knownTargets.get(label); } private String configurationToId(BuildConfiguration buildConfiguration) { if (!knownConfigurations.containsKey(buildConfiguration)) { String configurationId = String.valueOf(knownConfigurations.size()); knownConfigurations.put(buildConfiguration, configurationId); Configuration configurationProto = Configuration.newBuilder() .setMnemonic(buildConfiguration.getMnemonic()) .setPlatformName(buildConfiguration.getPlatformName()) .setId(configurationId) .build(); actionGraphBuilder.addConfiguration(configurationProto); } return knownConfigurations.get(buildConfiguration); } private String artifactToId(Artifact artifact) { if (!knownArtifacts.containsKey(artifact)) { String artifactId = String.valueOf(knownArtifacts.size()); knownArtifacts.put(artifact, artifactId); AnalysisProtos.Artifact artifactProto = AnalysisProtos.Artifact.newBuilder() .setId(artifactId) .setExecPath(artifact.getExecPathString()) .setIsTreeArtifact(artifact.isTreeArtifact()) .build(); actionGraphBuilder.addArtifacts(artifactProto); } return knownArtifacts.get(artifact); } private String depSetToId(NestedSetView nestedSetView) { if (!knownNestedSets.containsKey(nestedSetView.identifier())) { String nestedSetId = String.valueOf(knownNestedSets.size()); knownNestedSets.put(nestedSetView.identifier(), nestedSetId); DepSetOfFiles.Builder depSetBuilder = DepSetOfFiles.newBuilder().setId(nestedSetId); for (NestedSetView transitiveNestedSet : nestedSetView.transitives()) { depSetBuilder.addTransitiveDepSetIds(depSetToId(transitiveNestedSet)); } for (Artifact directArtifact : nestedSetView.directs()) { depSetBuilder.addDirectArtifactIds(artifactToId(directArtifact)); } actionGraphBuilder.addDepSetOfFiles(depSetBuilder.build()); } return knownNestedSets.get(nestedSetView.identifier()); } private String aspectDescriptorToId(AspectDescriptor aspectDescriptor) { if (!knownAspectDescriptors.containsKey(aspectDescriptor)) { String aspectDescriptorId = String.valueOf(knownAspectDescriptors.size()); knownAspectDescriptors.put(aspectDescriptor, aspectDescriptorId); AnalysisProtos.AspectDescriptor.Builder aspectDescriptorBuilder = AnalysisProtos.AspectDescriptor.newBuilder() .setId(aspectDescriptorId) .setName(aspectDescriptor.getAspectClass().getName()); for (Entry parameter : aspectDescriptor.getParameters().getAttributes().entries()) { KeyValuePair.Builder keyValuePairBuilder = KeyValuePair.newBuilder(); keyValuePairBuilder.setKey(parameter.getKey()).setValue(parameter.getValue()); aspectDescriptorBuilder.addParameters(keyValuePairBuilder.build()); } actionGraphBuilder.addAspectDescriptors(aspectDescriptorBuilder.build()); } return knownAspectDescriptors.get(aspectDescriptor); } private void dumpSingleAction(ConfiguredTarget configuredTarget, ActionAnalysisMetadata action) { Preconditions.checkState(configuredTarget instanceof RuleConfiguredTarget); Label label = configuredTarget.getLabel(); String ruleClassString = ((RuleConfiguredTarget) configuredTarget).getRuleClassString(); AnalysisProtos.Action.Builder actionBuilder = AnalysisProtos.Action.newBuilder() .setMnemonic(action.getMnemonic()) .setTargetId(targetToId(label, ruleClassString)); if (action instanceof ActionExecutionMetadata) { ActionExecutionMetadata actionExecutionMetadata = (ActionExecutionMetadata) action; actionBuilder .setActionKey(actionExecutionMetadata.getKey(getActionKeyContext())) .setDiscoversInputs(actionExecutionMetadata.discoversInputs()); } // store environment if (action instanceof SpawnAction) { SpawnAction spawnAction = (SpawnAction) action; // TODO(twerth): This handles the fixed environemnt. We probably want to output the inherited // environment as well. ImmutableMap fixedEnvironment = spawnAction.getEnvironment(); for (Entry environmentVariable : fixedEnvironment.entrySet()) { AnalysisProtos.KeyValuePair.Builder keyValuePairBuilder = AnalysisProtos.KeyValuePair.newBuilder(); keyValuePairBuilder .setKey(environmentVariable.getKey()) .setValue(environmentVariable.getValue()); actionBuilder.addEnvironmentVariables(keyValuePairBuilder.build()); } } ActionOwner actionOwner = action.getOwner(); if (actionOwner != null) { BuildConfiguration buildConfiguration = (BuildConfiguration) actionOwner.getConfiguration(); actionBuilder.setConfigurationId(configurationToId(buildConfiguration)); // store aspect for (AspectDescriptor aspectDescriptor : actionOwner.getAspectDescriptors()) { actionBuilder.addAspectDescriptorIds(aspectDescriptorToId(aspectDescriptor)); } } // store inputs Iterable inputs = action.getInputs(); if (!(inputs instanceof NestedSet)) { inputs = NestedSetBuilder.wrap(Order.STABLE_ORDER, inputs); } NestedSetView nestedSetView = new NestedSetView<>((NestedSet) inputs); if (nestedSetView.directs().size() > 0 || nestedSetView.transitives().size() > 0) { actionBuilder.addInputDepSetIds(depSetToId(nestedSetView)); } // store outputs for (Artifact artifact : action.getOutputs()) { actionBuilder.addOutputIds(artifactToId(artifact)); } actionGraphBuilder.addActions(actionBuilder.build()); } public void dumpAspect(AspectValue aspectValue, ConfiguredTargetValue configuredTargetValue) { ConfiguredTarget configuredTarget = configuredTargetValue.getConfiguredTarget(); if (!includeInActionGraph(configuredTarget.getLabel().toString())) { return; } for (int i = 0; i < aspectValue.getNumActions(); i++) { Action action = aspectValue.getAction(i); dumpSingleAction(configuredTarget, action); } } public void dumpConfiguredTarget(ConfiguredTargetValue configuredTargetValue) { ConfiguredTarget configuredTarget = configuredTargetValue.getConfiguredTarget(); if (!includeInActionGraph(configuredTarget.getLabel().toString())) { return; } List actions = configuredTargetValue.getActions(); for (ActionAnalysisMetadata action : actions) { dumpSingleAction(configuredTarget, action); } } public ActionGraphContainer build() { return actionGraphBuilder.build(); } }