1*333d2b36SAndroid Build Coastguard Worker// Copyright 2021 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage cc 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "fmt" 19*333d2b36SAndroid Build Coastguard Worker "strings" 20*333d2b36SAndroid Build Coastguard Worker 21*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 22*333d2b36SAndroid Build Coastguard Worker 23*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 24*333d2b36SAndroid Build Coastguard Worker) 25*333d2b36SAndroid Build Coastguard Worker 26*333d2b36SAndroid Build Coastguard Worker// This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering 27*333d2b36SAndroid Build Coastguard Workerconst afdoFlagsFormat = "-fprofile-sample-use=%s -fprofile-sample-accurate" 28*333d2b36SAndroid Build Coastguard Worker 29*333d2b36SAndroid Build Coastguard Workertype AfdoProperties struct { 30*333d2b36SAndroid Build Coastguard Worker // Afdo allows developers self-service enroll for 31*333d2b36SAndroid Build Coastguard Worker // automatic feedback-directed optimization using profile data. 32*333d2b36SAndroid Build Coastguard Worker Afdo bool 33*333d2b36SAndroid Build Coastguard Worker 34*333d2b36SAndroid Build Coastguard Worker AfdoDep bool `blueprint:"mutated"` 35*333d2b36SAndroid Build Coastguard Worker} 36*333d2b36SAndroid Build Coastguard Worker 37*333d2b36SAndroid Build Coastguard Workertype afdo struct { 38*333d2b36SAndroid Build Coastguard Worker Properties AfdoProperties 39*333d2b36SAndroid Build Coastguard Worker} 40*333d2b36SAndroid Build Coastguard Worker 41*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) props() []interface{} { 42*333d2b36SAndroid Build Coastguard Worker return []interface{}{&afdo.Properties} 43*333d2b36SAndroid Build Coastguard Worker} 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) begin(ctx BaseModuleContext) { 46*333d2b36SAndroid Build Coastguard Worker // Disable on eng builds for faster build. 47*333d2b36SAndroid Build Coastguard Worker if ctx.Config().Eng() { 48*333d2b36SAndroid Build Coastguard Worker afdo.Properties.Afdo = false 49*333d2b36SAndroid Build Coastguard Worker } 50*333d2b36SAndroid Build Coastguard Worker // Disable for native coverage builds. 51*333d2b36SAndroid Build Coastguard Worker if ctx.DeviceConfig().NativeCoverageEnabled() { 52*333d2b36SAndroid Build Coastguard Worker afdo.Properties.Afdo = false 53*333d2b36SAndroid Build Coastguard Worker } 54*333d2b36SAndroid Build Coastguard Worker} 55*333d2b36SAndroid Build Coastguard Worker 56*333d2b36SAndroid Build Coastguard Worker// afdoEnabled returns true for binaries and shared libraries 57*333d2b36SAndroid Build Coastguard Worker// that set afdo prop to True. 58*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) afdoEnabled() bool { 59*333d2b36SAndroid Build Coastguard Worker return afdo != nil && afdo.Properties.Afdo 60*333d2b36SAndroid Build Coastguard Worker} 61*333d2b36SAndroid Build Coastguard Worker 62*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) isAfdoCompile(ctx ModuleContext) bool { 63*333d2b36SAndroid Build Coastguard Worker fdoProfilePath := getFdoProfilePathFromDep(ctx) 64*333d2b36SAndroid Build Coastguard Worker return !ctx.Host() && (afdo.Properties.Afdo || afdo.Properties.AfdoDep) && (fdoProfilePath != "") 65*333d2b36SAndroid Build Coastguard Worker} 66*333d2b36SAndroid Build Coastguard Worker 67*333d2b36SAndroid Build Coastguard Workerfunc getFdoProfilePathFromDep(ctx ModuleContext) string { 68*333d2b36SAndroid Build Coastguard Worker fdoProfileDeps := ctx.GetDirectDepsWithTag(FdoProfileTag) 69*333d2b36SAndroid Build Coastguard Worker if len(fdoProfileDeps) > 0 && fdoProfileDeps[0] != nil { 70*333d2b36SAndroid Build Coastguard Worker if info, ok := android.OtherModuleProvider(ctx, fdoProfileDeps[0], FdoProfileProvider); ok { 71*333d2b36SAndroid Build Coastguard Worker return info.Path.String() 72*333d2b36SAndroid Build Coastguard Worker } 73*333d2b36SAndroid Build Coastguard Worker } 74*333d2b36SAndroid Build Coastguard Worker return "" 75*333d2b36SAndroid Build Coastguard Worker} 76*333d2b36SAndroid Build Coastguard Worker 77*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags { 78*333d2b36SAndroid Build Coastguard Worker if ctx.Host() { 79*333d2b36SAndroid Build Coastguard Worker return flags 80*333d2b36SAndroid Build Coastguard Worker } 81*333d2b36SAndroid Build Coastguard Worker 82*333d2b36SAndroid Build Coastguard Worker if afdo.Properties.Afdo || afdo.Properties.AfdoDep { 83*333d2b36SAndroid Build Coastguard Worker // Emit additional debug info for AutoFDO 84*333d2b36SAndroid Build Coastguard Worker flags.Local.CFlags = append([]string{"-fdebug-info-for-profiling"}, flags.Local.CFlags...) 85*333d2b36SAndroid Build Coastguard Worker // We use `-funique-internal-linkage-names` to associate profiles to the right internal 86*333d2b36SAndroid Build Coastguard Worker // functions. This option should be used before generating a profile. Because a profile 87*333d2b36SAndroid Build Coastguard Worker // generated for a binary without unique names doesn't work well building a binary with 88*333d2b36SAndroid Build Coastguard Worker // unique names (they have different internal function names). 89*333d2b36SAndroid Build Coastguard Worker // To avoid a chicken-and-egg problem, we enable `-funique-internal-linkage-names` when 90*333d2b36SAndroid Build Coastguard Worker // `afdo=true`, whether a profile exists or not. 91*333d2b36SAndroid Build Coastguard Worker // The profile can take effect in three steps: 92*333d2b36SAndroid Build Coastguard Worker // 1. Add `afdo: true` in Android.bp, and build the binary. 93*333d2b36SAndroid Build Coastguard Worker // 2. Collect an AutoFDO profile for the binary. 94*333d2b36SAndroid Build Coastguard Worker // 3. Make the profile searchable by the build system. So it's used the next time the binary 95*333d2b36SAndroid Build Coastguard Worker // is built. 96*333d2b36SAndroid Build Coastguard Worker flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...) 97*333d2b36SAndroid Build Coastguard Worker // Flags for Flow Sensitive AutoFDO 98*333d2b36SAndroid Build Coastguard Worker flags.Local.CFlags = append([]string{"-mllvm", "-enable-fs-discriminator=true"}, flags.Local.CFlags...) 99*333d2b36SAndroid Build Coastguard Worker // TODO(b/266595187): Remove the following feature once it is enabled in LLVM by default. 100*333d2b36SAndroid Build Coastguard Worker flags.Local.CFlags = append([]string{"-mllvm", "-improved-fs-discriminator=true"}, flags.Local.CFlags...) 101*333d2b36SAndroid Build Coastguard Worker } 102*333d2b36SAndroid Build Coastguard Worker if fdoProfilePath := getFdoProfilePathFromDep(ctx); fdoProfilePath != "" { 103*333d2b36SAndroid Build Coastguard Worker // The flags are prepended to allow overriding. 104*333d2b36SAndroid Build Coastguard Worker profileUseFlag := fmt.Sprintf(afdoFlagsFormat, fdoProfilePath) 105*333d2b36SAndroid Build Coastguard Worker flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...) 106*333d2b36SAndroid Build Coastguard Worker flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...) 107*333d2b36SAndroid Build Coastguard Worker 108*333d2b36SAndroid Build Coastguard Worker // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt 109*333d2b36SAndroid Build Coastguard Worker // if profileFile gets updated 110*333d2b36SAndroid Build Coastguard Worker pathForSrc := android.PathForSource(ctx, fdoProfilePath) 111*333d2b36SAndroid Build Coastguard Worker flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc) 112*333d2b36SAndroid Build Coastguard Worker flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc) 113*333d2b36SAndroid Build Coastguard Worker } 114*333d2b36SAndroid Build Coastguard Worker 115*333d2b36SAndroid Build Coastguard Worker return flags 116*333d2b36SAndroid Build Coastguard Worker} 117*333d2b36SAndroid Build Coastguard Worker 118*333d2b36SAndroid Build Coastguard Workerfunc (a *afdo) addDep(ctx android.BottomUpMutatorContext, fdoProfileTarget string) { 119*333d2b36SAndroid Build Coastguard Worker if fdoProfileName, err := ctx.DeviceConfig().AfdoProfile(fdoProfileTarget); fdoProfileName != "" && err == nil { 120*333d2b36SAndroid Build Coastguard Worker ctx.AddFarVariationDependencies( 121*333d2b36SAndroid Build Coastguard Worker []blueprint.Variation{ 122*333d2b36SAndroid Build Coastguard Worker {Mutator: "arch", Variation: ctx.Target().ArchVariation()}, 123*333d2b36SAndroid Build Coastguard Worker {Mutator: "os", Variation: "android"}, 124*333d2b36SAndroid Build Coastguard Worker }, 125*333d2b36SAndroid Build Coastguard Worker FdoProfileTag, 126*333d2b36SAndroid Build Coastguard Worker fdoProfileName) 127*333d2b36SAndroid Build Coastguard Worker } 128*333d2b36SAndroid Build Coastguard Worker} 129*333d2b36SAndroid Build Coastguard Worker 130*333d2b36SAndroid Build Coastguard Workerfunc afdoPropagateViaDepTag(tag blueprint.DependencyTag) bool { 131*333d2b36SAndroid Build Coastguard Worker libTag, isLibTag := tag.(libraryDependencyTag) 132*333d2b36SAndroid Build Coastguard Worker // Do not recurse down non-static dependencies 133*333d2b36SAndroid Build Coastguard Worker if isLibTag { 134*333d2b36SAndroid Build Coastguard Worker return libTag.static() 135*333d2b36SAndroid Build Coastguard Worker } else { 136*333d2b36SAndroid Build Coastguard Worker return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag 137*333d2b36SAndroid Build Coastguard Worker } 138*333d2b36SAndroid Build Coastguard Worker} 139*333d2b36SAndroid Build Coastguard Worker 140*333d2b36SAndroid Build Coastguard Worker// afdoTransitionMutator creates afdo variants of cc modules. 141*333d2b36SAndroid Build Coastguard Workertype afdoTransitionMutator struct{} 142*333d2b36SAndroid Build Coastguard Worker 143*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) Split(ctx android.BaseModuleContext) []string { 144*333d2b36SAndroid Build Coastguard Worker return []string{""} 145*333d2b36SAndroid Build Coastguard Worker} 146*333d2b36SAndroid Build Coastguard Worker 147*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { 148*333d2b36SAndroid Build Coastguard Worker if ctx.Host() { 149*333d2b36SAndroid Build Coastguard Worker return "" 150*333d2b36SAndroid Build Coastguard Worker } 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { 153*333d2b36SAndroid Build Coastguard Worker if !afdoPropagateViaDepTag(ctx.DepTag()) { 154*333d2b36SAndroid Build Coastguard Worker return "" 155*333d2b36SAndroid Build Coastguard Worker } 156*333d2b36SAndroid Build Coastguard Worker 157*333d2b36SAndroid Build Coastguard Worker if sourceVariation != "" { 158*333d2b36SAndroid Build Coastguard Worker return sourceVariation 159*333d2b36SAndroid Build Coastguard Worker } 160*333d2b36SAndroid Build Coastguard Worker 161*333d2b36SAndroid Build Coastguard Worker if !m.afdo.afdoEnabled() { 162*333d2b36SAndroid Build Coastguard Worker return "" 163*333d2b36SAndroid Build Coastguard Worker } 164*333d2b36SAndroid Build Coastguard Worker 165*333d2b36SAndroid Build Coastguard Worker // TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but 166*333d2b36SAndroid Build Coastguard Worker // it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies. 167*333d2b36SAndroid Build Coastguard Worker if m.static() { 168*333d2b36SAndroid Build Coastguard Worker return "" 169*333d2b36SAndroid Build Coastguard Worker } 170*333d2b36SAndroid Build Coastguard Worker 171*333d2b36SAndroid Build Coastguard Worker return encodeTarget(ctx.Module().Name()) 172*333d2b36SAndroid Build Coastguard Worker } 173*333d2b36SAndroid Build Coastguard Worker return "" 174*333d2b36SAndroid Build Coastguard Worker} 175*333d2b36SAndroid Build Coastguard Worker 176*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { 177*333d2b36SAndroid Build Coastguard Worker if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { 178*333d2b36SAndroid Build Coastguard Worker return incomingVariation 179*333d2b36SAndroid Build Coastguard Worker } 180*333d2b36SAndroid Build Coastguard Worker return "" 181*333d2b36SAndroid Build Coastguard Worker} 182*333d2b36SAndroid Build Coastguard Worker 183*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { 184*333d2b36SAndroid Build Coastguard Worker if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { 185*333d2b36SAndroid Build Coastguard Worker if !m.Enabled(ctx) { 186*333d2b36SAndroid Build Coastguard Worker return 187*333d2b36SAndroid Build Coastguard Worker } 188*333d2b36SAndroid Build Coastguard Worker if variation == "" { 189*333d2b36SAndroid Build Coastguard Worker // The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO 190*333d2b36SAndroid Build Coastguard Worker // variant of a dependency. 191*333d2b36SAndroid Build Coastguard Worker if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() { 192*333d2b36SAndroid Build Coastguard Worker m.afdo.addDep(ctx, ctx.ModuleName()) 193*333d2b36SAndroid Build Coastguard Worker } 194*333d2b36SAndroid Build Coastguard Worker } else { 195*333d2b36SAndroid Build Coastguard Worker // The non-empty variation is the AFDO variant of a dependency of a module that enabled AFDO 196*333d2b36SAndroid Build Coastguard Worker // for itself. 197*333d2b36SAndroid Build Coastguard Worker m.Properties.PreventInstall = true 198*333d2b36SAndroid Build Coastguard Worker m.Properties.HideFromMake = true 199*333d2b36SAndroid Build Coastguard Worker m.afdo.Properties.AfdoDep = true 200*333d2b36SAndroid Build Coastguard Worker m.afdo.addDep(ctx, decodeTarget(variation)) 201*333d2b36SAndroid Build Coastguard Worker } 202*333d2b36SAndroid Build Coastguard Worker } 203*333d2b36SAndroid Build Coastguard Worker} 204*333d2b36SAndroid Build Coastguard Worker 205*333d2b36SAndroid Build Coastguard Worker// Encode target name to variation name. 206*333d2b36SAndroid Build Coastguard Workerfunc encodeTarget(target string) string { 207*333d2b36SAndroid Build Coastguard Worker if target == "" { 208*333d2b36SAndroid Build Coastguard Worker return "" 209*333d2b36SAndroid Build Coastguard Worker } 210*333d2b36SAndroid Build Coastguard Worker return "afdo-" + target 211*333d2b36SAndroid Build Coastguard Worker} 212*333d2b36SAndroid Build Coastguard Worker 213*333d2b36SAndroid Build Coastguard Worker// Decode target name from variation name. 214*333d2b36SAndroid Build Coastguard Workerfunc decodeTarget(variation string) string { 215*333d2b36SAndroid Build Coastguard Worker if variation == "" { 216*333d2b36SAndroid Build Coastguard Worker return "" 217*333d2b36SAndroid Build Coastguard Worker } 218*333d2b36SAndroid Build Coastguard Worker return strings.TrimPrefix(variation, "afdo-") 219*333d2b36SAndroid Build Coastguard Worker} 220