bloaty: measure stripped Rust binaries

Modify bloaty's MeasureSizeForPath to allow a module to provide multiple
paths. This is used to measure both unstripped and stripped
libraries/binaries. Add unit test to ensure correct measurements are
generated for Rust.

Test: m out/soong/binary_sizes.pb.gz
Change-Id: I59439b77dbf1cf5ad71e1c02996a6a90938536b4
This commit is contained in:
Thiébaud Weksteen 2021-04-14 11:18:47 +02:00
parent 4fab05a2ad
commit e4dd14b25f
7 changed files with 76 additions and 19 deletions

View file

@ -11,6 +11,7 @@ bootstrap_go_package {
], ],
srcs: [ srcs: [
"bloaty.go", "bloaty.go",
"testing.go",
], ],
pluginFor: ["soong_build"], pluginFor: ["soong_build"],
} }

View file

@ -52,12 +52,28 @@ func init() {
pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty") pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger") pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
android.RegisterSingletonType("file_metrics", fileSizesSingleton) android.RegisterSingletonType("file_metrics", fileSizesSingleton)
fileSizeMeasurerKey = blueprint.NewProvider(android.ModuleOutPath{}) fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{})
} }
// MeasureSizeForPath should be called by binary producers (e.g. in builder.go). // measuredFiles contains the paths of the files measured by a module.
func MeasureSizeForPath(ctx android.ModuleContext, filePath android.WritablePath) { type measuredFiles struct {
ctx.SetProvider(fileSizeMeasurerKey, filePath) paths []android.WritablePath
}
// MeasureSizeForPaths should be called by binary producers to measure the
// sizes of artifacts. It must only be called once per module; it will panic
// otherwise.
func MeasureSizeForPaths(ctx android.ModuleContext, paths ...android.OptionalPath) {
mf := measuredFiles{}
for _, p := range paths {
if !p.Valid() {
continue
}
if p, ok := p.Path().(android.WritablePath); ok {
mf.paths = append(mf.paths, p)
}
}
ctx.SetProvider(fileSizeMeasurerKey, mf)
} }
type sizesSingleton struct{} type sizesSingleton struct{}
@ -68,21 +84,22 @@ func fileSizesSingleton() android.Singleton {
func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) { func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var deps android.Paths var deps android.Paths
// Visit all modules. If the size provider give us a binary path to measure,
// create the rule to measure it.
ctx.VisitAllModules(func(m android.Module) { ctx.VisitAllModules(func(m android.Module) {
if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) { if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
return return
} }
filePath := ctx.ModuleProvider(m, fileSizeMeasurerKey).(android.ModuleOutPath) filePaths := ctx.ModuleProvider(m, fileSizeMeasurerKey).(measuredFiles)
sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt) for _, path := range filePaths.paths {
ctx.Build(pctx, android.BuildParams{ filePath := path.(android.ModuleOutPath)
Rule: bloaty, sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
Description: "bloaty " + filePath.Rel(), ctx.Build(pctx, android.BuildParams{
Input: filePath, Rule: bloaty,
Output: sizeFile, Description: "bloaty " + filePath.Rel(),
}) Input: filePath,
deps = append(deps, sizeFile) Output: sizeFile,
})
deps = append(deps, sizeFile)
}
}) })
ctx.Build(pctx, android.BuildParams{ ctx.Build(pctx, android.BuildParams{

25
bloaty/testing.go Normal file
View file

@ -0,0 +1,25 @@
// Copyright 2021 Google Inc. 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 bloaty
import (
"android/soong/android"
)
// Preparer that will define the default bloaty singleton.
var PrepareForTestWithBloatyDefaultModules = android.GroupFixturePreparers(
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
ctx.RegisterSingletonType("file_metrics", fileSizesSingleton)
}))

View file

@ -21,7 +21,6 @@ import (
"github.com/google/blueprint" "github.com/google/blueprint"
"android/soong/android" "android/soong/android"
"android/soong/bloaty"
"android/soong/rust/config" "android/soong/rust/config"
) )
@ -254,8 +253,6 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl
implicits = append(implicits, clippyFile) implicits = append(implicits, clippyFile)
} }
bloaty.MeasureSizeForPath(ctx, outputFile)
ctx.Build(pctx, android.BuildParams{ ctx.Build(pctx, android.BuildParams{
Rule: rustc, Rule: rustc,
Description: "rustc " + main.Rel(), Description: "rustc " + main.Rel(),

View file

@ -22,6 +22,7 @@ import (
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
"android/soong/android" "android/soong/android"
"android/soong/bloaty"
"android/soong/cc" "android/soong/cc"
cc_config "android/soong/cc/config" cc_config "android/soong/cc/config"
"android/soong/rust/config" "android/soong/rust/config"
@ -731,8 +732,8 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
if mod.compiler != nil && !mod.compiler.Disabled() { if mod.compiler != nil && !mod.compiler.Disabled() {
mod.compiler.initialize(ctx) mod.compiler.initialize(ctx)
unstrippedOutputFile := mod.compiler.compile(ctx, flags, deps) unstrippedOutputFile := mod.compiler.compile(ctx, flags, deps)
mod.unstrippedOutputFile = android.OptionalPathForPath(unstrippedOutputFile) mod.unstrippedOutputFile = android.OptionalPathForPath(unstrippedOutputFile)
bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), mod.unstrippedOutputFile)
apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo) apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if mod.installable(apexInfo) { if mod.installable(apexInfo) {

View file

@ -384,3 +384,17 @@ func TestMultilib(t *testing.T) {
_ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std") _ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std")
_ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std") _ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std")
} }
// Test that library size measurements are generated.
func TestLibrarySizes(t *testing.T) {
ctx := testRust(t, `
rust_library_dylib {
name: "libwaldo",
srcs: ["foo.rs"],
crate_name: "waldo",
}`)
m := ctx.SingletonForTests("file_metrics")
m.Output("libwaldo.dylib.so.bloaty.csv")
m.Output("stripped/libwaldo.dylib.so.bloaty.csv")
}

View file

@ -16,6 +16,7 @@ package rust
import ( import (
"android/soong/android" "android/soong/android"
"android/soong/bloaty"
"android/soong/cc" "android/soong/cc"
) )
@ -34,6 +35,7 @@ const rustDefaultsDir = "defaults/rust/"
// Preparer that will define default rust modules, e.g. standard prebuilt modules. // Preparer that will define default rust modules, e.g. standard prebuilt modules.
var PrepareForTestWithRustDefaultModules = android.GroupFixturePreparers( var PrepareForTestWithRustDefaultModules = android.GroupFixturePreparers(
cc.PrepareForTestWithCcDefaultModules, cc.PrepareForTestWithCcDefaultModules,
bloaty.PrepareForTestWithBloatyDefaultModules,
PrepareForTestWithRustBuildComponents, PrepareForTestWithRustBuildComponents,
android.FixtureAddTextFile(rustDefaultsDir+"Android.bp", GatherRequiredDepsForTest()), android.FixtureAddTextFile(rustDefaultsDir+"Android.bp", GatherRequiredDepsForTest()),
) )