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