Preserve depset structure from bazel aquery

Each depset now corresponds to a phony rule which depends on other
depsets or on full paths; thus, bazel's depset structure is preserved in
the form of phony rules of name bazel_depset_{id}.

Previously, flattening and recopying large lists of file path strings
was quite inefficient. This was particularly evident as we enumerated
hundreds of clang headers for each cc compile action.

This reduces soong_build analysis time by about 30% for mixed builds.
It also reduces ninja file size by ~750MB.

Fixes: 229405615
Test: Unit tests, manually verified metrics, mixed_droid CI

Change-Id: I78df152ac1488ae0c6807afdde4b4ad5e6d26287
This commit is contained in:
Chris Parsons
2022-04-25 22:35:15 -04:00
parent 126bd58e72
commit 1a7aca075b
3 changed files with 476 additions and 185 deletions

View File

@@ -28,6 +28,7 @@ import (
"android/soong/bazel/cquery"
"android/soong/shared"
"github.com/google/blueprint"
"android/soong/bazel"
)
@@ -101,6 +102,9 @@ type BazelContext interface {
// Returns build statements which should get registered to reflect Bazel's outputs.
BuildStatementsToRegister() []bazel.BuildStatement
// Returns the depsets defined in Bazel's aquery response.
AqueryDepsets() []bazel.AqueryDepset
}
type bazelRunner interface {
@@ -128,6 +132,9 @@ type bazelContext struct {
// Build statements which should get registered to reflect Bazel's outputs.
buildStatements []bazel.BuildStatement
// Depsets which should be used for Bazel's build statements.
depsets []bazel.AqueryDepset
}
var _ BazelContext = &bazelContext{}
@@ -175,6 +182,10 @@ func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
return []bazel.BuildStatement{}
}
func (m MockBazelContext) AqueryDepsets() []bazel.AqueryDepset {
return []bazel.AqueryDepset{}
}
var _ BazelContext = MockBazelContext{}
func (bazelCtx *bazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, bool) {
@@ -236,6 +247,10 @@ func (m noopBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
return []bazel.BuildStatement{}
}
func (m noopBazelContext) AqueryDepsets() []bazel.AqueryDepset {
return []bazel.AqueryDepset{}
}
func NewBazelContext(c *config) (BazelContext, error) {
// TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
// are production ready.
@@ -746,7 +761,7 @@ func (context *bazelContext) InvokeBazel() error {
return err
}
context.buildStatements, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
if err != nil {
return err
}
@@ -772,6 +787,10 @@ func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement
return context.buildStatements
}
func (context *bazelContext) AqueryDepsets() []bazel.AqueryDepset {
return context.depsets
}
func (context *bazelContext) OutputBase() string {
return context.paths.outputBase
}
@@ -804,6 +823,23 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
ctx.AddNinjaFileDeps(file)
}
for _, depset := range ctx.Config().BazelContext.AqueryDepsets() {
var outputs []Path
for _, depsetDepId := range depset.TransitiveDepSetIds {
otherDepsetName := bazelDepsetName(depsetDepId)
outputs = append(outputs, PathForPhony(ctx, otherDepsetName))
}
for _, artifactPath := range depset.DirectArtifacts {
outputs = append(outputs, PathForBazelOut(ctx, artifactPath))
}
thisDepsetName := bazelDepsetName(depset.Id)
ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
Outputs: []WritablePath{PathForPhony(ctx, thisDepsetName)},
Implicits: outputs,
})
}
// Register bazel-owned build statements (obtained from the aquery invocation).
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
if len(buildStatement.Command) < 1 {
@@ -838,6 +874,10 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
for _, inputPath := range buildStatement.InputPaths {
cmd.Implicit(PathForBazelOut(ctx, inputPath))
}
for _, inputDepsetId := range buildStatement.InputDepsetIds {
otherDepsetName := bazelDepsetName(inputDepsetId)
cmd.Implicit(PathForPhony(ctx, otherDepsetName))
}
if depfile := buildStatement.Depfile; depfile != nil {
cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
@@ -882,3 +922,7 @@ func GetConfigKey(ctx ModuleContext) configKey {
osType: ctx.Os(),
}
}
func bazelDepsetName(depsetId int) string {
return fmt.Sprintf("bazel_depset_%d", depsetId)
}