diff --git a/rust/Android.bp b/rust/Android.bp index a29c474b1..a6c4e0787 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -14,6 +14,7 @@ bootstrap_go_package { ], srcs: [ "androidmk.go", + "benchmark.go", "binary.go", "bindgen.go", "builder.go", @@ -35,6 +36,7 @@ bootstrap_go_package { "testing.go", ], testSrcs: [ + "benchmark_test.go", "binary_test.go", "bindgen_test.go", "builder_test.go", diff --git a/rust/androidmk.go b/rust/androidmk.go index dea32a34d..940710e63 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -107,6 +107,20 @@ func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidM cc.AndroidMkWriteTestData(test.data, ret) } +func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { + benchmark.binaryDecorator.AndroidMk(ctx, ret) + ret.Class = "NATIVE_TESTS" + ret.ExtraEntries = append(ret.ExtraEntries, + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...) + if benchmark.testConfig != nil { + entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String()) + } + entries.SetBool("LOCAL_NATIVE_BENCHMARK", true) + entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(benchmark.Properties.Auto_gen_config, true)) + }) +} + func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { ctx.SubAndroidMk(ret, library.baseCompiler) diff --git a/rust/benchmark.go b/rust/benchmark.go new file mode 100644 index 000000000..b89f5cd9b --- /dev/null +++ b/rust/benchmark.go @@ -0,0 +1,129 @@ +// Copyright 2020 The Android Open Source Project +// +// 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 rust + +import ( + "android/soong/android" + "android/soong/tradefed" +) + +type BenchmarkProperties struct { + // Disables the creation of a test-specific directory when used with + // relative_install_path. Useful if several tests need to be in the same + // directory, but test_per_src doesn't work. + No_named_install_directory *bool + + // the name of the test configuration (for example "AndroidBenchmark.xml") that should be + // installed with the module. + Test_config *string `android:"path,arch_variant"` + + // the name of the test configuration template (for example "AndroidBenchmarkTemplate.xml") that + // should be installed with the module. + Test_config_template *string `android:"path,arch_variant"` + + // list of compatibility suites (for example "cts", "vts") that the module should be + // installed into. + Test_suites []string `android:"arch_variant"` + + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml + // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true + // explicitly. + Auto_gen_config *bool +} + +type benchmarkDecorator struct { + *binaryDecorator + Properties BenchmarkProperties + testConfig android.Path +} + +func NewRustBenchmark(hod android.HostOrDeviceSupported) (*Module, *benchmarkDecorator) { + // Build both 32 and 64 targets for device benchmarks. + // Cannot build both for host benchmarks yet if the benchmark depends on + // something like proc-macro2 that cannot be built for both. + multilib := android.MultilibBoth + if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported { + multilib = android.MultilibFirst + } + module := newModule(hod, multilib) + + benchmark := &benchmarkDecorator{ + binaryDecorator: &binaryDecorator{ + baseCompiler: NewBaseCompiler("nativebench", "nativebench64", InstallInData), + }, + } + + module.compiler = benchmark + module.AddProperties(&benchmark.Properties) + return module, benchmark +} + +func init() { + android.RegisterModuleType("rust_benchmark", RustBenchmarkFactory) + android.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory) +} + +func RustBenchmarkFactory() android.Module { + module, _ := NewRustBenchmark(android.HostAndDeviceSupported) + return module.Init() +} + +func RustBenchmarkHostFactory() android.Module { + module, _ := NewRustBenchmark(android.HostSupported) + return module.Init() +} + +func (benchmark *benchmarkDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { + return rlibAutoDep +} + +func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage { + return RlibLinkage +} + +func (benchmark *benchmarkDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { + flags = benchmark.binaryDecorator.compilerFlags(ctx, flags) + return flags +} + +func (benchmark *benchmarkDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { + deps = benchmark.binaryDecorator.compilerDeps(ctx, deps) + + deps.Rustlibs = append(deps.Rustlibs, "libcriterion") + + return deps +} + +func (benchmark *benchmarkDecorator) compilerProps() []interface{} { + return append(benchmark.binaryDecorator.compilerProps(), &benchmark.Properties) +} + +func (benchmark *benchmarkDecorator) install(ctx ModuleContext) { + benchmark.testConfig = tradefed.AutoGenRustBenchmarkConfig(ctx, + benchmark.Properties.Test_config, + benchmark.Properties.Test_config_template, + benchmark.Properties.Test_suites, + nil, + benchmark.Properties.Auto_gen_config) + + // default relative install path is module name + if !Bool(benchmark.Properties.No_named_install_directory) { + benchmark.baseCompiler.relative = ctx.ModuleName() + } else if String(benchmark.baseCompiler.Properties.Relative_install_path) == "" { + ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set") + } + + benchmark.binaryDecorator.install(ctx) +} diff --git a/rust/benchmark_test.go b/rust/benchmark_test.go new file mode 100644 index 000000000..734dda71d --- /dev/null +++ b/rust/benchmark_test.go @@ -0,0 +1,54 @@ +// Copyright 2021 The Android Open Source Project +// +// 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 rust + +import ( + "strings" + "testing" + + "android/soong/android" +) + +func TestRustBenchmark(t *testing.T) { + ctx := testRust(t, ` + rust_benchmark_host { + name: "my_bench", + srcs: ["foo.rs"], + }`) + + testingModule := ctx.ModuleForTests("my_bench", "linux_glibc_x86_64") + expectedOut := "my_bench/linux_glibc_x86_64/my_bench" + outPath := testingModule.Output("my_bench").Output.String() + if !strings.Contains(outPath, expectedOut) { + t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut) + } +} + +func TestRustBenchmarkLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_benchmark { + name: "my_bench", + srcs: ["foo.rs"], + }`) + + testingModule := ctx.ModuleForTests("my_bench", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libcriterion.rlib-std", testingModule.Properties.AndroidMkRlibs) { + t.Errorf("rlib-std variant for libcriterion not detected as a rustlib-defined rlib dependency for device rust_benchmark module") + } + if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) { + t.Errorf("Device rust_benchmark module 'my_bench' does not link libstd as an rlib") + } +} diff --git a/rust/rust.go b/rust/rust.go index 34e197a07..ca85d74cc 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -434,6 +434,7 @@ func DefaultsFactory(props ...interface{}) android.Module { module.AddProperties( &BaseProperties{}, &cc.VendorProperties{}, + &BenchmarkProperties{}, &BindgenProperties{}, &BaseCompilerProperties{}, &BinaryCompilerProperties{}, diff --git a/rust/testing.go b/rust/testing.go index 75adcfce9..1e01cc0c5 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -192,11 +192,19 @@ func GatherRequiredDepsForTest() string { srcs:["foo.rs"], host_supported: true, } + rust_library { + name: "libcriterion", + crate_name: "criterion", + srcs:["foo.rs"], + host_supported: true, + } ` return bp } func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { + ctx.RegisterModuleType("rust_benchmark", RustBenchmarkFactory) + ctx.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory) ctx.RegisterModuleType("rust_binary", RustBinaryFactory) ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory) ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory) diff --git a/tradefed/autogen.go b/tradefed/autogen.go index 27d71e828..3d96c8457 100644 --- a/tradefed/autogen.go +++ b/tradefed/autogen.go @@ -245,6 +245,25 @@ func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string, return path } +func AutoGenRustBenchmarkConfig(ctx android.ModuleContext, testConfigProp *string, + testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp) + if autogenPath != nil { + templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) + if templatePath.Valid() { + autogenTemplate(ctx, autogenPath, templatePath.String(), config, "") + } else { + if ctx.Device() { + autogenTemplate(ctx, autogenPath, "${RustDeviceBenchmarkConfigTemplate}", config, "") + } else { + autogenTemplate(ctx, autogenPath, "${RustHostBenchmarkConfigTemplate}", config, "") + } + } + return autogenPath + } + return path +} + func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path { path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp) diff --git a/tradefed/config.go b/tradefed/config.go index f3566a80d..999424cfb 100644 --- a/tradefed/config.go +++ b/tradefed/config.go @@ -34,6 +34,8 @@ func init() { pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml") pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml") pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml") + pctx.SourcePathVariable("RustDeviceBenchmarkConfigTemplate", "build/make/core/rust_device_benchmark_config_template.xml") + pctx.SourcePathVariable("RustHostBenchmarkConfigTemplate", "build/make/core/rust_host_benchmark_config_template.xml") pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml") pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml") diff --git a/tradefed/makevars.go b/tradefed/makevars.go index f9682e448..9b5a20f47 100644 --- a/tradefed/makevars.go +++ b/tradefed/makevars.go @@ -33,6 +33,8 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("PYTHON_BINARY_HOST_TEST_CONFIG_TEMPLATE", "${PythonBinaryHostTestConfigTemplate}") ctx.Strict("RUST_DEVICE_TEST_CONFIG_TEMPLATE", "${RustDeviceTestConfigTemplate}") ctx.Strict("RUST_HOST_TEST_CONFIG_TEMPLATE", "${RustHostTestConfigTemplate}") + ctx.Strict("RUST_DEVICE_BENCHMARK_CONFIG_TEMPLATE", "${RustDeviceBenchmarkConfigTemplate}") + ctx.Strict("RUST_HOST_BENCHMARK_CONFIG_TEMPLATE", "${RustHostBenchmarkConfigTemplate}") ctx.Strict("SHELL_TEST_CONFIG_TEMPLATE", "${ShellTestConfigTemplate}") ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}")