blob: 69a74f0c2eb160f00a84d36087372ebd1b7cacd0 [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.query2.aquery;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.analysis.AspectValue;
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
import com.google.devtools.build.lib.skyframe.RuleConfiguredTargetValue;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/** Output callback for aquery, prints a human readable summary. */
class ActionGraphSummaryOutputFormatterCallback extends AqueryThreadsafeCallback {
private final AqueryActionFilter actionFilters;
private final Map<String, Integer> mnemonicToCount = new HashMap<>();
private final Map<String, Integer> configurationToCount = new HashMap<>();
private final Map<String, Integer> execPlatformToCount = new HashMap<>();
private final Map<String, Integer> aspectToCount = new HashMap<>();
ActionGraphSummaryOutputFormatterCallback(
ExtendedEventHandler eventHandler,
AqueryOptions options,
OutputStream out,
TargetAccessor<ConfiguredTargetValue> accessor,
AqueryActionFilter actionFilters) {
super(eventHandler, options, out, accessor);
this.actionFilters = actionFilters;
}
@Override
public String getName() {
return "summary";
}
@Override
public void processOutput(Iterable<ConfiguredTargetValue> partialResult)
throws IOException, InterruptedException {
// Enabling includeParamFiles should enable includeCommandline by default.
options.includeCommandline |= options.includeParamFiles;
for (ConfiguredTargetValue configuredTargetValue : partialResult) {
if (!(configuredTargetValue instanceof RuleConfiguredTargetValue)) {
// We have to include non-rule values in the graph to visit their dependencies, but they
// don't have any actions to print out.
continue;
}
for (ActionAnalysisMetadata action :
((RuleConfiguredTargetValue) configuredTargetValue).getActions()) {
processAction(action);
}
if (options.useAspects) {
for (AspectValue aspectValue : accessor.getAspectValues(configuredTargetValue)) {
for (ActionAnalysisMetadata action : aspectValue.getActions()) {
processAction(action);
}
}
}
}
}
private void processAction(ActionAnalysisMetadata action) throws InterruptedException {
if (!AqueryUtils.matchesAqueryFilters(action, actionFilters)) {
return;
}
mnemonicToCount.merge(action.getMnemonic(), 1, Integer::sum);
ActionOwner actionOwner = action.getOwner();
if (actionOwner != null) {
BuildEvent configuration = actionOwner.getBuildConfigurationEvent();
BuildEventStreamProtos.Configuration configProto =
configuration.asStreamProto(/*context=*/ null).getConfiguration();
configurationToCount.merge(configProto.getMnemonic(), 1, Integer::sum);
if (actionOwner.getExecutionPlatform() != null) {
execPlatformToCount.merge(
actionOwner.getExecutionPlatform().label().toString(), 1, Integer::sum);
}
// In the case of aspect-on-aspect, AspectDescriptors are listed in
// topological order of the dependency graph.
// e.g. [A -> B] would imply that aspect A is applied on top of aspect B.
ImmutableList<AspectDescriptor> aspectDescriptors =
actionOwner.getAspectDescriptors().reverse();
if (!aspectDescriptors.isEmpty()) {
aspectDescriptors.forEach(
aspectDescriptor ->
aspectToCount.merge(aspectDescriptor.getAspectClass().getName(), 1, Integer::sum));
}
}
}
@Override
public void close(boolean failFast) throws InterruptedException, IOException {
if (failFast) {
return;
}
int totalActions = mnemonicToCount.values().stream().mapToInt(v -> v).sum();
if (totalActions == 0) {
printStream.println("No actions matched.");
} else {
printStream.println(totalActions + " total action" + (totalActions == 1 ? "" : "s") + ".");
}
printSummary(mnemonicToCount, "Mnemonics:");
printSummary(configurationToCount, "Configurations:");
printSummary(execPlatformToCount, "Execution Platforms:");
printSummary(aspectToCount, "Aspects:");
}
private void printSummary(Map<String, Integer> actionsCount, String s) {
if (!actionsCount.isEmpty()) {
printStream.println();
printStream.println(s);
actionsCount.entrySet().stream()
.sorted(Comparator.comparingInt(Entry::getValue))
.forEach(entry -> printStream.println(" " + entry.getKey() + ": " + entry.getValue()));
}
}
}