blob: 0539c03fde7f89028139568484b1aca789c1a81b [file] [log] [blame]
// 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<Artifact, String> knownArtifacts = new HashMap<>();
private final Map<BuildConfiguration, String> knownConfigurations = new HashMap<>();
private final Map<Label, String> knownTargets = new HashMap<>();
private final Map<AspectDescriptor, String> knownAspectDescriptors = new HashMap<>();
private final Map<String, String> knownRuleClassStrings = new HashMap<>();
// The NestedSet is identified by their raw 'children' object since multiple NestedSetViews
// can point to the same object.
private final Map<Object, String> knownNestedSets = new HashMap<>();
private final ActionGraphContainer.Builder actionGraphBuilder = ActionGraphContainer.newBuilder();
private final ActionKeyContext actionKeyContext = new ActionKeyContext();
private final Set<String> actionGraphTargets;
public ActionGraphDump(List<String> 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<Artifact> 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<Artifact> 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<String, String> 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<String, String> fixedEnvironment = spawnAction.getEnvironment();
for (Entry<String, String> 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<Artifact> inputs = action.getInputs();
if (!(inputs instanceof NestedSet)) {
inputs = NestedSetBuilder.wrap(Order.STABLE_ORDER, inputs);
}
NestedSetView<Artifact> nestedSetView = new NestedSetView<>((NestedSet<Artifact>) 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<ActionAnalysisMetadata> actions = configuredTargetValue.getActions();
for (ActionAnalysisMetadata action : actions) {
dumpSingleAction(configuredTarget, action);
}
}
public ActionGraphContainer build() {
return actionGraphBuilder.build();
}
}