afdo.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright 2021 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package cc
  15. import (
  16. "fmt"
  17. "strings"
  18. "android/soong/android"
  19. "github.com/google/blueprint"
  20. "github.com/google/blueprint/proptools"
  21. )
  22. // TODO(b/267229066): Remove globalAfdoProfileProjects after implementing bp2build converter for fdo_profile
  23. var (
  24. globalAfdoProfileProjects = []string{
  25. "vendor/google_data/pgo_profile/sampling/",
  26. "toolchain/pgo-profiles/sampling/",
  27. }
  28. )
  29. var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
  30. const afdoCFlagsFormat = "-fprofile-sample-use=%s"
  31. func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
  32. getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
  33. }
  34. type afdoRdep struct {
  35. VariationName *string
  36. ProfilePath *string
  37. }
  38. type AfdoProperties struct {
  39. // Afdo allows developers self-service enroll for
  40. // automatic feedback-directed optimization using profile data.
  41. Afdo bool
  42. FdoProfilePath *string `blueprint:"mutated"`
  43. AfdoRDeps []afdoRdep `blueprint:"mutated"`
  44. }
  45. type afdo struct {
  46. Properties AfdoProperties
  47. }
  48. func (afdo *afdo) props() []interface{} {
  49. return []interface{}{&afdo.Properties}
  50. }
  51. // afdoEnabled returns true for binaries and shared libraries
  52. // that set afdo prop to True and there is a profile available
  53. func (afdo *afdo) afdoEnabled() bool {
  54. return afdo != nil && afdo.Properties.Afdo
  55. }
  56. func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
  57. if afdo.Properties.Afdo {
  58. // We use `-funique-internal-linkage-names` to associate profiles to the right internal
  59. // functions. This option should be used before generating a profile. Because a profile
  60. // generated for a binary without unique names doesn't work well building a binary with
  61. // unique names (they have different internal function names).
  62. // To avoid a chicken-and-egg problem, we enable `-funique-internal-linkage-names` when
  63. // `afdo=true`, whether a profile exists or not.
  64. // The profile can take effect in three steps:
  65. // 1. Add `afdo: true` in Android.bp, and build the binary.
  66. // 2. Collect an AutoFDO profile for the binary.
  67. // 3. Make the profile searchable by the build system. So it's used the next time the binary
  68. // is built.
  69. flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...)
  70. }
  71. if path := afdo.Properties.FdoProfilePath; path != nil {
  72. // The flags are prepended to allow overriding.
  73. profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
  74. flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...)
  75. flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...)
  76. // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
  77. // if profileFile gets updated
  78. pathForSrc := android.PathForSource(ctx, *path)
  79. flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc)
  80. flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc)
  81. }
  82. return flags
  83. }
  84. func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
  85. if ctx.Host() {
  86. return
  87. }
  88. if ctx.static() && !ctx.staticBinary() {
  89. return
  90. }
  91. if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
  92. if fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()); fdoProfileName != nil && err == nil {
  93. actx.AddFarVariationDependencies(
  94. []blueprint.Variation{
  95. {Mutator: "arch", Variation: actx.Target().ArchVariation()},
  96. {Mutator: "os", Variation: "android"},
  97. },
  98. FdoProfileTag,
  99. []string{*fdoProfileName}...,
  100. )
  101. }
  102. }
  103. }
  104. // FdoProfileMutator reads the FdoProfileProvider from a direct dep with FdoProfileTag
  105. // assigns FdoProfileInfo.Path to the FdoProfilePath mutated property
  106. func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
  107. if !c.Enabled() {
  108. return
  109. }
  110. ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
  111. if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
  112. info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
  113. c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
  114. }
  115. })
  116. }
  117. var _ FdoProfileMutatorInterface = (*Module)(nil)
  118. // Propagate afdo requirements down from binaries and shared libraries
  119. func afdoDepsMutator(mctx android.TopDownMutatorContext) {
  120. if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
  121. path := m.afdo.Properties.FdoProfilePath
  122. mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
  123. tag := mctx.OtherModuleDependencyTag(dep)
  124. libTag, isLibTag := tag.(libraryDependencyTag)
  125. // Do not recurse down non-static dependencies
  126. if isLibTag {
  127. if !libTag.static() {
  128. return false
  129. }
  130. } else {
  131. if tag != objDepTag && tag != reuseObjTag {
  132. return false
  133. }
  134. }
  135. if dep, ok := dep.(*Module); ok {
  136. dep.afdo.Properties.AfdoRDeps = append(
  137. dep.afdo.Properties.AfdoRDeps,
  138. afdoRdep{
  139. VariationName: proptools.StringPtr(encodeTarget(m.Name())),
  140. ProfilePath: path,
  141. },
  142. )
  143. }
  144. return true
  145. })
  146. }
  147. }
  148. // Create afdo variants for modules that need them
  149. func afdoMutator(mctx android.BottomUpMutatorContext) {
  150. if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
  151. if !m.static() && m.afdo.Properties.Afdo {
  152. mctx.SetDependencyVariation(encodeTarget(m.Name()))
  153. return
  154. }
  155. variationNames := []string{""}
  156. variantNameToProfilePath := make(map[string]*string)
  157. for _, afdoRDep := range m.afdo.Properties.AfdoRDeps {
  158. variantName := *afdoRDep.VariationName
  159. // An rdep can be set twice in AfdoRDeps because there can be
  160. // more than one path from an afdo-enabled module to
  161. // a static dep such as
  162. // afdo_enabled_foo -> static_bar ----> static_baz
  163. // \ ^
  164. // ----------------------|
  165. // We only need to create one variant per unique rdep
  166. if _, exists := variantNameToProfilePath[variantName]; !exists {
  167. variationNames = append(variationNames, variantName)
  168. variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
  169. }
  170. }
  171. if len(variationNames) > 1 {
  172. modules := mctx.CreateVariations(variationNames...)
  173. for i, name := range variationNames {
  174. if name == "" {
  175. continue
  176. }
  177. variation := modules[i].(*Module)
  178. variation.Properties.PreventInstall = true
  179. variation.Properties.HideFromMake = true
  180. variation.afdo.Properties.Afdo = true
  181. variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
  182. }
  183. }
  184. }
  185. }
  186. // Encode target name to variation name.
  187. func encodeTarget(target string) string {
  188. if target == "" {
  189. return ""
  190. }
  191. return "afdo-" + target
  192. }
  193. // Decode target name from variation name.
  194. func decodeTarget(variation string) string {
  195. if variation == "" {
  196. return ""
  197. }
  198. return strings.TrimPrefix(variation, "afdo-")
  199. }