summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/config.go15
-rw-r--r--android/variable.go2
-rw-r--r--cc/Android.bp2
-rw-r--r--cc/afdo.go191
-rw-r--r--cc/afdo_test.go182
-rw-r--r--cc/cc.go11
-rw-r--r--cc/fdo_profile.go85
-rw-r--r--cc/testing.go6
-rw-r--r--rust/afdo.go47
-rw-r--r--rust/afdo_test.go48
-rw-r--r--rust/rust.go5
11 files changed, 448 insertions, 146 deletions
diff --git a/android/config.go b/android/config.go
index 038cd0f19..5cd6062f3 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1418,6 +1418,21 @@ func (c *deviceConfig) PgoAdditionalProfileDirs() []string {
return c.config.productVariables.PgoAdditionalProfileDirs
}
+// AfdoProfile returns fully qualified path associated to the given module name
+func (c *deviceConfig) AfdoProfile(name string) (*string, error) {
+ for _, afdoProfile := range c.config.productVariables.AfdoProfiles {
+ split := strings.Split(afdoProfile, ":")
+ if len(split) != 3 {
+ return nil, fmt.Errorf("AFDO_PROFILES has invalid value: %s. "+
+ "The expected format is <module>:<fully-qualified-path-to-fdo_profile>", afdoProfile)
+ }
+ if split[0] == name {
+ return proptools.StringPtr(strings.Join([]string{split[1], split[2]}, ":")), nil
+ }
+ }
+ return nil, nil
+}
+
func (c *deviceConfig) VendorSepolicyDirs() []string {
return c.config.productVariables.BoardVendorSepolicyDirs
}
diff --git a/android/variable.go b/android/variable.go
index 1da5974ea..249d53b07 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -464,6 +464,8 @@ type productVariables struct {
IncludeTags []string `json:",omitempty"`
SourceRootDirs []string `json:",omitempty"`
+
+ AfdoProfiles []string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
diff --git a/cc/Android.bp b/cc/Android.bp
index 5fd9afea9..be2cc5a34 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -21,6 +21,8 @@ bootstrap_go_package {
],
srcs: [
"afdo.go",
+ "fdo_profile.go",
+
"androidmk.go",
"api_level.go",
"bp2build.go",
diff --git a/cc/afdo.go b/cc/afdo.go
index d36f4afcf..4a8498bc7 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -18,11 +18,13 @@ import (
"fmt"
"strings"
- "github.com/google/blueprint/proptools"
-
"android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
+// TODO(b/267229066): Remove globalAfdoProfileProjects after implementing bp2build converter for fdo_profile
var (
globalAfdoProfileProjects = []string{
"vendor/google_data/pgo_profile/sampling/",
@@ -34,23 +36,23 @@ var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
const afdoCFlagsFormat = "-funique-internal-linkage-names -fprofile-sample-accurate -fprofile-sample-use=%s"
-func getAfdoProfileProjects(config android.DeviceConfig) []string {
- return config.OnceStringSlice(afdoProfileProjectsConfigKey, func() []string {
- return globalAfdoProfileProjects
- })
-}
-
func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
}
+type afdoRdep struct {
+ VariationName *string
+ ProfilePath *string
+}
+
type AfdoProperties struct {
// Afdo allows developers self-service enroll for
// automatic feedback-directed optimization using profile data.
Afdo bool
- AfdoTarget *string `blueprint:"mutated"`
- AfdoDeps []string `blueprint:"mutated"`
+ FdoProfilePath *string `blueprint:"mutated"`
+
+ AfdoRDeps []afdoRdep `blueprint:"mutated"`
}
type afdo struct {
@@ -61,116 +63,131 @@ func (afdo *afdo) props() []interface{} {
return []interface{}{&afdo.Properties}
}
-func (afdo *afdo) AfdoEnabled() bool {
- return afdo != nil && afdo.Properties.Afdo && afdo.Properties.AfdoTarget != nil
+// afdoEnabled returns true for binaries and shared libraries
+// that set afdo prop to True and there is a profile available
+func (afdo *afdo) afdoEnabled() bool {
+ return afdo != nil && afdo.Properties.Afdo && afdo.Properties.FdoProfilePath != nil
}
-// Get list of profile file names, ordered by level of specialisation. For example:
-// 1. libfoo_arm64.afdo
-// 2. libfoo.afdo
-//
-// Add more specialisation as needed.
-func getProfileFiles(ctx android.BaseModuleContext, moduleName string) []string {
- var files []string
- files = append(files, moduleName+"_"+ctx.Arch().ArchType.String()+".afdo")
- files = append(files, moduleName+".afdo")
- return files
-}
-
-func (props *AfdoProperties) GetAfdoProfileFile(ctx android.BaseModuleContext, module string) android.OptionalPath {
- // Test if the profile_file is present in any of the Afdo profile projects
- for _, profileFile := range getProfileFiles(ctx, module) {
- for _, profileProject := range getAfdoProfileProjects(ctx.DeviceConfig()) {
- path := android.ExistentPathForSource(ctx, profileProject, profileFile)
- if path.Valid() {
- return path
- }
- }
+func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
+ if path := afdo.Properties.FdoProfilePath; path != nil {
+ profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
+ flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
+
+ // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+ // if profileFile gets updated
+ pathForSrc := android.PathForSource(ctx, *path)
+ flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc)
+ flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc)
}
- // Record that this module's profile file is absent
- missing := ctx.ModuleDir() + ":" + module
- recordMissingAfdoProfileFile(ctx, missing)
-
- return android.OptionalPathForPath(nil)
+ return flags
}
-func (afdo *afdo) begin(ctx BaseModuleContext) {
+func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
if ctx.Host() {
return
}
+
if ctx.static() && !ctx.staticBinary() {
return
}
- if afdo.Properties.Afdo {
- module := ctx.ModuleName()
- if afdo.Properties.GetAfdoProfileFile(ctx, module).Valid() {
- afdo.Properties.AfdoTarget = proptools.StringPtr(module)
+
+ if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
+ if fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()); fdoProfileName != nil && err == nil {
+ actx.AddFarVariationDependencies(
+ []blueprint.Variation{
+ {Mutator: "arch", Variation: actx.Target().ArchVariation()},
+ {Mutator: "os", Variation: "android"},
+ },
+ FdoProfileTag,
+ []string{*fdoProfileName}...,
+ )
}
}
}
-func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
- if profile := afdo.Properties.AfdoTarget; profile != nil {
- if profileFile := afdo.Properties.GetAfdoProfileFile(ctx, *profile); profileFile.Valid() {
- profileFilePath := profileFile.Path()
-
- profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, profileFile)
- flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
- flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
-
- // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
- // if profileFile gets updated
- flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
- flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
- }
+// FdoProfileMutator reads the FdoProfileProvider from a direct dep with FdoProfileTag
+// assigns FdoProfileInfo.Path to the FdoProfilePath mutated property
+func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
+ if !c.Enabled() {
+ return
}
- return flags
+ ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
+ if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
+ info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
+ c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
+ }
+ })
}
-// Propagate afdo requirements down from binaries
+var _ FdoProfileMutatorInterface = (*Module)(nil)
+
+// Propagate afdo requirements down from binaries and shared libraries
func afdoDepsMutator(mctx android.TopDownMutatorContext) {
- if m, ok := mctx.Module().(*Module); ok && m.afdo.AfdoEnabled() {
- afdoTarget := *m.afdo.Properties.AfdoTarget
- mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
- tag := mctx.OtherModuleDependencyTag(dep)
- libTag, isLibTag := tag.(libraryDependencyTag)
-
- // Do not recurse down non-static dependencies
- if isLibTag {
- if !libTag.static() {
- return false
+ if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
+ if path := m.afdo.Properties.FdoProfilePath; path != nil {
+ mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+ tag := mctx.OtherModuleDependencyTag(dep)
+ libTag, isLibTag := tag.(libraryDependencyTag)
+
+ // Do not recurse down non-static dependencies
+ if isLibTag {
+ if !libTag.static() {
+ return false
+ }
+ } else {
+ if tag != objDepTag && tag != reuseObjTag {
+ return false
+ }
}
- } else {
- if tag != objDepTag && tag != reuseObjTag {
- return false
- }
- }
- if dep, ok := dep.(*Module); ok {
- dep.afdo.Properties.AfdoDeps = append(dep.afdo.Properties.AfdoDeps, afdoTarget)
- }
+ if dep, ok := dep.(*Module); ok {
+ dep.afdo.Properties.AfdoRDeps = append(
+ dep.afdo.Properties.AfdoRDeps,
+ afdoRdep{
+ VariationName: proptools.StringPtr(encodeTarget(m.Name())),
+ ProfilePath: path,
+ },
+ )
+ }
- return true
- })
+ return true
+ })
+ }
}
}
// Create afdo variants for modules that need them
func afdoMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
- if m.afdo.AfdoEnabled() && !m.static() {
- afdoTarget := *m.afdo.Properties.AfdoTarget
- mctx.SetDependencyVariation(encodeTarget(afdoTarget))
+ if !m.static() && m.afdo.Properties.Afdo && m.afdo.Properties.FdoProfilePath != nil {
+ mctx.SetDependencyVariation(encodeTarget(m.Name()))
+ return
}
variationNames := []string{""}
- afdoDeps := android.FirstUniqueStrings(m.afdo.Properties.AfdoDeps)
- for _, dep := range afdoDeps {
- variationNames = append(variationNames, encodeTarget(dep))
+
+ variantNameToProfilePath := make(map[string]*string)
+
+ for _, afdoRDep := range m.afdo.Properties.AfdoRDeps {
+ variantName := *afdoRDep.VariationName
+ // An rdep can be set twice in AfdoRDeps because there can be
+ // more than one path from an afdo-enabled module to
+ // a static dep such as
+ // afdo_enabled_foo -> static_bar ----> static_baz
+ // \ ^
+ // ----------------------|
+ // We only need to create one variant per unique rdep
+ if variantNameToProfilePath[variantName] == nil {
+ variationNames = append(variationNames, variantName)
+ variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
+ }
}
+
if len(variationNames) > 1 {
modules := mctx.CreateVariations(variationNames...)
for i, name := range variationNames {
@@ -180,7 +197,7 @@ func afdoMutator(mctx android.BottomUpMutatorContext) {
variation := modules[i].(*Module)
variation.Properties.PreventInstall = true
variation.Properties.HideFromMake = true
- variation.afdo.Properties.AfdoTarget = proptools.StringPtr(decodeTarget(name))
+ variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
}
}
}
diff --git a/cc/afdo_test.go b/cc/afdo_test.go
index 40f705b87..1c20bfc8c 100644
--- a/cc/afdo_test.go
+++ b/cc/afdo_test.go
@@ -58,38 +58,77 @@ func TestAfdoDeps(t *testing.T) {
srcs: ["bar.c"],
}
`
- prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libTest.afdo", "TEST")
result := android.GroupFixturePreparers(
+ PrepareForTestWithFdoProfile,
prepareForCcTest,
- prepareForAfdoTest,
+ android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AfdoProfiles = []string{
+ "libTest://afdo_profiles_package:libTest_afdo",
+ }
+ }),
+ android.MockFS{
+ "afdo_profiles_package/Android.bp": []byte(`
+ fdo_profile {
+ name: "libTest_afdo",
+ profile: "libTest.afdo",
+ }
+ `),
+ }.AddToFixture(),
).RunTestWithBp(t, bp)
+ expectedCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
+
libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
- libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
- libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
+ libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
+ libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
+
+ // Check cFlags of afdo-enabled module and the afdo-variant of its static deps
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
- if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+ cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check dependency edge from afdo-enabled module to static deps
+ if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) {
t.Errorf("libTest missing dependency on afdo variant of libFoo")
}
- if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+ if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) {
t.Errorf("libTest missing dependency on afdo variant of libBar")
}
- cFlags := libTest.Rule("cc").Args["cFlags"]
- if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) {
- t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", w, cFlags)
- }
+ // Verify non-afdo variant exists and doesn't contain afdo
+ libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+ libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
cFlags = libFoo.Rule("cc").Args["cFlags"]
- if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) {
- t.Errorf("Expected 'libFoo' to enable afdo, but did not find %q in cflags %q", w, cFlags)
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
}
-
cFlags = libBar.Rule("cc").Args["cFlags"]
- if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) {
- t.Errorf("Expected 'libBar' to enable afdo, but did not find %q in cflags %q", w, cFlags)
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check dependency edges of static deps
+ if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+ t.Errorf("libTest should not depend on non-afdo variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+ t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
}
}
@@ -113,11 +152,21 @@ func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) {
name: "libBar",
}
`
- prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libFoo.afdo", "TEST")
result := android.GroupFixturePreparers(
prepareForCcTest,
- prepareForAfdoTest,
+ PrepareForTestWithFdoProfile,
+ android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libFoo.afdo", ""),
+ android.MockFS{
+ "afdo_profiles_package/Android.bp": []byte(`
+ soong_namespace {
+ }
+ fdo_profile {
+ name: "libFoo_afdo",
+ profile: "libFoo.afdo",
+ }
+ `),
+ }.AddToFixture(),
).RunTestWithBp(t, bp)
libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared").Module()
@@ -150,7 +199,6 @@ func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) {
t.Errorf("Expected no afdo variant of 'bar', got %q", v)
}
}
-
}
func TestAfdoEnabledWithRuntimeDepNoAfdo(t *testing.T) {
@@ -166,11 +214,24 @@ func TestAfdoEnabledWithRuntimeDepNoAfdo(t *testing.T) {
name: "libFoo",
}
`
- prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libTest.afdo", "TEST")
result := android.GroupFixturePreparers(
prepareForCcTest,
- prepareForAfdoTest,
+ PrepareForTestWithFdoProfile,
+ android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AfdoProfiles = []string{
+ "libTest://afdo_profiles_package:libTest_afdo",
+ }
+ }),
+ android.MockFS{
+ "afdo_profiles_package/Android.bp": []byte(`
+ fdo_profile {
+ name: "libTest_afdo",
+ profile: "libTest.afdo",
+ }
+ `),
+ }.AddToFixture(),
).RunTestWithBp(t, bp)
libFooVariants := result.ModuleVariantsForTests("libFoo")
@@ -182,7 +243,6 @@ func TestAfdoEnabledWithRuntimeDepNoAfdo(t *testing.T) {
}
func TestAfdoEnabledWithMultiArchs(t *testing.T) {
- t.Parallel()
bp := `
cc_library_shared {
name: "foo",
@@ -192,20 +252,43 @@ func TestAfdoEnabledWithMultiArchs(t *testing.T) {
}
`
result := android.GroupFixturePreparers(
+ PrepareForTestWithFdoProfile,
prepareForCcTest,
- android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm.afdo", "TEST"),
- android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm64.afdo", "TEST"),
+ android.FixtureAddTextFile("afdo_profiles_package/foo_arm.afdo", ""),
+ android.FixtureAddTextFile("afdo_profiles_package/foo_arm64.afdo", ""),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AfdoProfiles = []string{
+ "foo://afdo_profiles_package:foo_afdo",
+ }
+ }),
+ android.MockFS{
+ "afdo_profiles_package/Android.bp": []byte(`
+ soong_namespace {
+ }
+ fdo_profile {
+ name: "foo_afdo",
+ arch: {
+ arm: {
+ profile: "foo_arm.afdo",
+ },
+ arm64: {
+ profile: "foo_arm64.afdo",
+ }
+ }
+ }
+ `),
+ }.AddToFixture(),
).RunTestWithBp(t, bp)
fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared")
fooArmCFlags := fooArm.Rule("cc").Args["cFlags"]
- if w := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/foo_arm.afdo"; !strings.Contains(fooArmCFlags, w) {
+ if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm.afdo"; !strings.Contains(fooArmCFlags, w) {
t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArmCFlags)
}
fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a_shared")
fooArm64CFlags := fooArm64.Rule("cc").Args["cFlags"]
- if w := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/foo_arm64.afdo"; !strings.Contains(fooArm64CFlags, w) {
+ if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm64.afdo"; !strings.Contains(fooArm64CFlags, w) {
t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArm64CFlags)
}
}
@@ -234,46 +317,65 @@ func TestMultipleAfdoRDeps(t *testing.T) {
`
result := android.GroupFixturePreparers(
+ PrepareForTestWithFdoProfile,
prepareForCcTest,
- android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libTest.afdo", "TEST"),
- android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libBar.afdo", "TEST"),
+ android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
+ android.FixtureAddTextFile("afdo_profiles_package/libBar.afdo", ""),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AfdoProfiles = []string{
+ "libTest://afdo_profiles_package:libTest_afdo",
+ "libBar://afdo_profiles_package:libBar_afdo",
+ }
+ }),
+ android.MockFS{
+ "afdo_profiles_package/Android.bp": []byte(`
+ fdo_profile {
+ name: "libTest_afdo",
+ profile: "libTest.afdo",
+ }
+ fdo_profile {
+ name: "libBar_afdo",
+ profile: "libBar.afdo",
+ }
+ `),
+ }.AddToFixture(),
).RunTestWithBp(t, bp)
- expectedCFlagLibTest := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/libTest.afdo"
- expectedCFlagLibBar := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/libBar.afdo"
+ expectedCFlagLibTest := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
+ expectedCFlagLibBar := "-fprofile-sample-use=afdo_profiles_package/libBar.afdo"
libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
- libTestAfdoVariantOfLibFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
+ libFooAfdoVariantWithLibTest := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_shared")
- libBarAfdoVariantOfLibFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libBar")
+ libFooAfdoVariantWithLibBar := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libBar")
- // Check cFlags of afdo-enabled modules and the afdo-variant of their static deps
+ // Check cFlags of afdo-enabled module and the afdo-variant of its static deps
cFlags := libTest.Rule("cc").Args["cFlags"]
if !strings.Contains(cFlags, expectedCFlagLibTest) {
t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
}
cFlags = libBar.Rule("cc").Args["cFlags"]
if !strings.Contains(cFlags, expectedCFlagLibBar) {
- t.Errorf("Expected 'libBar' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
+ t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
}
- cFlags = libTestAfdoVariantOfLibFoo.Rule("cc").Args["cFlags"]
+ cFlags = libFooAfdoVariantWithLibTest.Rule("cc").Args["cFlags"]
if !strings.Contains(cFlags, expectedCFlagLibTest) {
- t.Errorf("Expected 'libTestAfdoVariantOfLibFoo' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
+ t.Errorf("Expected 'libFooAfdoVariantWithLibTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
}
- cFlags = libBarAfdoVariantOfLibFoo.Rule("cc").Args["cFlags"]
+ cFlags = libFooAfdoVariantWithLibBar.Rule("cc").Args["cFlags"]
if !strings.Contains(cFlags, expectedCFlagLibBar) {
- t.Errorf("Expected 'libBarAfdoVariantOfLibFoo' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
+ t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
}
// Check dependency edges of static deps
- if !hasDirectDep(result, libTest.Module(), libTestAfdoVariantOfLibFoo.Module()) {
+ if !hasDirectDep(result, libTest.Module(), libFooAfdoVariantWithLibTest.Module()) {
t.Errorf("libTest missing dependency on afdo variant of libFoo")
}
- if !hasDirectDep(result, libBar.Module(), libBarAfdoVariantOfLibFoo.Module()) {
- t.Errorf("libBar missing dependency on afdo variant of libFoo")
+ if !hasDirectDep(result, libBar.Module(), libFooAfdoVariantWithLibBar.Module()) {
+ t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
}
}
diff --git a/cc/cc.go b/cc/cc.go
index b029d712e..9c555a11e 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -52,6 +52,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
ctx.BottomUp("version", versionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
+ ctx.BottomUp("fdo_profile", fdoProfileMutator)
})
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -763,6 +764,7 @@ var (
testPerSrcDepTag = dependencyTag{name: "test_per_src"}
stubImplDepTag = dependencyTag{name: "stub_impl"}
JniFuzzLibTag = dependencyTag{name: "jni_fuzz_lib_tag"}
+ FdoProfileTag = dependencyTag{name: "fdo_profile"}
)
func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
@@ -1336,7 +1338,7 @@ func (c *Module) IsVndk() bool {
func (c *Module) isAfdoCompile() bool {
if afdo := c.afdo; afdo != nil {
- return afdo.Properties.AfdoTarget != nil
+ return afdo.Properties.FdoProfilePath != nil
}
return false
}
@@ -2162,9 +2164,6 @@ func (c *Module) begin(ctx BaseModuleContext) {
if c.lto != nil {
c.lto.begin(ctx)
}
- if c.afdo != nil {
- c.afdo.begin(ctx)
- }
if c.pgo != nil {
c.pgo.begin(ctx)
}
@@ -2239,6 +2238,10 @@ func (c *Module) beginMutator(actx android.BottomUpMutatorContext) {
}
ctx.ctx = ctx
+ if !actx.Host() || !ctx.static() || ctx.staticBinary() {
+ c.afdo.addDep(ctx, actx)
+ }
+
c.begin(ctx)
}
diff --git a/cc/fdo_profile.go b/cc/fdo_profile.go
new file mode 100644
index 000000000..7fbe71940
--- /dev/null
+++ b/cc/fdo_profile.go
@@ -0,0 +1,85 @@
+// Copyright 2023 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 cc
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+func init() {
+ RegisterFdoProfileBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterFdoProfileBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("fdo_profile", fdoProfileFactory)
+}
+
+type fdoProfile struct {
+ android.ModuleBase
+
+ properties fdoProfileProperties
+}
+
+type fdoProfileProperties struct {
+ Profile *string `android:"arch_variant"`
+}
+
+// FdoProfileInfo is provided by FdoProfileProvider
+type FdoProfileInfo struct {
+ Path android.Path
+}
+
+// FdoProfileProvider is used to provide path to an fdo profile
+var FdoProfileProvider = blueprint.NewMutatorProvider(FdoProfileInfo{}, "fdo_profile")
+
+// FdoProfileMutatorInterface is the interface implemented by fdo_profile module type
+// module types that can depend on an fdo_profile module
+type FdoProfileMutatorInterface interface {
+ // FdoProfileMutator eithers set or get FdoProfileProvider
+ fdoProfileMutator(ctx android.BottomUpMutatorContext)
+}
+
+var _ FdoProfileMutatorInterface = (*fdoProfile)(nil)
+
+// GenerateAndroidBuildActions of fdo_profile does not have any build actions
+func (fp *fdoProfile) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+// FdoProfileMutator sets FdoProfileProvider to fdo_profile module
+// or sets afdo.Properties.FdoProfilePath to path in FdoProfileProvider of the depended fdo_profile
+func (fp *fdoProfile) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
+ if fp.properties.Profile != nil {
+ path := android.PathForModuleSrc(ctx, *fp.properties.Profile)
+ ctx.SetProvider(FdoProfileProvider, FdoProfileInfo{
+ Path: path,
+ })
+ }
+}
+
+// fdoProfileMutator calls the generic fdoProfileMutator function of fdoProfileMutator
+// which is implemented by cc and cc.FdoProfile
+func fdoProfileMutator(ctx android.BottomUpMutatorContext) {
+ if f, ok := ctx.Module().(FdoProfileMutatorInterface); ok {
+ f.fdoProfileMutator(ctx)
+ }
+}
+
+func fdoProfileFactory() android.Module {
+ m := &fdoProfile{}
+ m.AddProperties(&m.properties)
+ android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibBoth)
+ return m
+}
diff --git a/cc/testing.go b/cc/testing.go
index f78ea0f80..ced09290f 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -670,6 +670,12 @@ var PrepareForTestWithHostMusl = android.GroupFixturePreparers(
`),
)
+// PrepareForTestWithFdoProfile registers module types to test with fdo_profile
+var PrepareForTestWithFdoProfile = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("soong_namespace", android.NamespaceFactory)
+ ctx.RegisterModuleType("fdo_profile", fdoProfileFactory)
+})
+
// TestConfig is the legacy way of creating a test Config for testing cc modules.
//
// See testCc for an explanation as to how to stop using this deprecated method.
diff --git a/rust/afdo.go b/rust/afdo.go
index 996fd7e0c..3534ee6e4 100644
--- a/rust/afdo.go
+++ b/rust/afdo.go
@@ -17,7 +17,10 @@ package rust
import (
"fmt"
+ "android/soong/android"
"android/soong/cc"
+
+ "github.com/google/blueprint"
)
const afdoFlagFormat = "-Zprofile-sample-use=%s"
@@ -30,19 +33,49 @@ func (afdo *afdo) props() []interface{} {
return []interface{}{&afdo.Properties}
}
-func (afdo *afdo) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
+ // afdo is not supported outside of Android
+ if ctx.Host() {
+ return
+ }
+
+ if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() {
+ fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName())
+ if err != nil {
+ ctx.ModuleErrorf("%s", err.Error())
+ }
+ if fdoProfileName != nil {
+ actx.AddFarVariationDependencies(
+ []blueprint.Variation{
+ {Mutator: "arch", Variation: actx.Target().ArchVariation()},
+ {Mutator: "os", Variation: "android"},
+ },
+ cc.FdoProfileTag,
+ []string{*fdoProfileName}...,
+ )
+ }
+ }
+}
+
+func (afdo *afdo) flags(ctx android.ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
if ctx.Host() {
return flags, deps
}
- if afdo != nil && afdo.Properties.Afdo {
- if profileFile := afdo.Properties.GetAfdoProfileFile(ctx, ctx.ModuleName()); profileFile.Valid() {
- profileUseFlag := fmt.Sprintf(afdoFlagFormat, profileFile)
+ if !afdo.Properties.Afdo {
+ return flags, deps
+ }
+
+ ctx.VisitDirectDepsWithTag(cc.FdoProfileTag, func(m android.Module) {
+ if ctx.OtherModuleHasProvider(m, cc.FdoProfileProvider) {
+ info := ctx.OtherModuleProvider(m, cc.FdoProfileProvider).(cc.FdoProfileInfo)
+ path := info.Path
+ profileUseFlag := fmt.Sprintf(afdoFlagFormat, path.String())
flags.RustFlags = append(flags.RustFlags, profileUseFlag)
- profileFilePath := profileFile.Path()
- deps.AfdoProfiles = append(deps.AfdoProfiles, profileFilePath)
+ deps.AfdoProfiles = append(deps.AfdoProfiles, path)
}
- }
+ })
+
return flags, deps
}
diff --git a/rust/afdo_test.go b/rust/afdo_test.go
index fa20eef26..0cdf70491 100644
--- a/rust/afdo_test.go
+++ b/rust/afdo_test.go
@@ -16,6 +16,7 @@ package rust
import (
"android/soong/android"
+ "android/soong/cc"
"fmt"
"strings"
"testing"
@@ -31,13 +32,27 @@ func TestAfdoEnabled(t *testing.T) {
`
result := android.GroupFixturePreparers(
prepareForRustTest,
- android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo.afdo", ""),
+ cc.PrepareForTestWithFdoProfile,
+ android.FixtureAddTextFile("afdo_profiles_package/foo.afdo", ""),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AfdoProfiles = []string{
+ "foo://afdo_profiles_package:foo_afdo",
+ }
+ }),
+ android.MockFS{
+ "afdo_profiles_package/Android.bp": []byte(`
+ fdo_profile {
+ name: "foo_afdo",
+ profile: "foo.afdo",
+ }
+ `),
+ }.AddToFixture(),
rustMockedFiles.AddToFixture(),
).RunTestWithBp(t, bp)
foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
- expectedCFlag := fmt.Sprintf(afdoFlagFormat, "toolchain/pgo-profiles/sampling/foo.afdo")
+ expectedCFlag := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo.afdo")
if !strings.Contains(foo.Args["rustcFlags"], expectedCFlag) {
t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", expectedCFlag, foo.Args["rustcFlags"])
@@ -55,16 +70,37 @@ func TestAfdoEnabledWithMultiArchs(t *testing.T) {
`
result := android.GroupFixturePreparers(
prepareForRustTest,
- android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm.afdo", ""),
- android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm64.afdo", ""),
+ cc.PrepareForTestWithFdoProfile,
+ android.FixtureAddTextFile("afdo_profiles_package/foo_arm.afdo", ""),
+ android.FixtureAddTextFile("afdo_profiles_package/foo_arm64.afdo", ""),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AfdoProfiles = []string{
+ "foo://afdo_profiles_package:foo_afdo",
+ }
+ }),
+ android.MockFS{
+ "afdo_profiles_package/Android.bp": []byte(`
+ fdo_profile {
+ name: "foo_afdo",
+ arch: {
+ arm: {
+ profile: "foo_arm.afdo",
+ },
+ arm64: {
+ profile: "foo_arm64.afdo",
+ }
+ }
+ }
+ `),
+ }.AddToFixture(),
rustMockedFiles.AddToFixture(),
).RunTestWithBp(t, bp)
fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Rule("rustc")
fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
- expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "toolchain/pgo-profiles/sampling/foo_arm.afdo")
- expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "toolchain/pgo-profiles/sampling/foo_arm64.afdo")
+ expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm.afdo")
+ expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm64.afdo")
if !strings.Contains(fooArm.Args["rustcFlags"], expectedCFlagArm) {
t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm, fooArm.Args["rustcFlags"])
diff --git a/rust/rust.go b/rust/rust.go
index 1c4349597..56b463160 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -39,7 +39,6 @@ func init() {
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
-
})
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
@@ -920,7 +919,7 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
// Calculate rustc flags
if mod.afdo != nil {
- flags, deps = mod.afdo.flags(ctx, flags, deps)
+ flags, deps = mod.afdo.flags(actx, flags, deps)
}
if mod.compiler != nil {
flags = mod.compiler.compilerFlags(ctx, flags)
@@ -1613,6 +1612,8 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
+
+ mod.afdo.addDep(ctx, actx)
}
// addRlibDependency will add an rlib dependency, rewriting to the snapshot library if available.