| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 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 |  | 
|  | 15 | package cc | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 18 | "fmt" | 
|  | 19 | "strings" | 
|  | 20 |  | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 21 | "android/soong/android" | 
| Vinh Tran | 44cb78c | 2023-03-09 22:07:19 -0500 | [diff] [blame] | 22 |  | 
|  | 23 | "github.com/google/blueprint" | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 24 | ) | 
|  | 25 |  | 
| Vinh Tran | 056effb | 2023-06-27 14:03:25 +0000 | [diff] [blame] | 26 | // This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering | 
| Yi Kong | 0880a82 | 2023-11-14 23:49:40 +0000 | [diff] [blame] | 27 | const afdoFlagsFormat = "-fprofile-sample-use=%s -fprofile-sample-accurate" | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 28 |  | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 29 | type AfdoProperties struct { | 
| Alix | 40216ae | 2022-04-07 20:47:01 +0000 | [diff] [blame] | 30 | // Afdo allows developers self-service enroll for | 
|  | 31 | // automatic feedback-directed optimization using profile data. | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 32 | Afdo bool | 
|  | 33 |  | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 34 | AfdoDep bool `blueprint:"mutated"` | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 35 | } | 
|  | 36 |  | 
|  | 37 | type afdo struct { | 
|  | 38 | Properties AfdoProperties | 
|  | 39 | } | 
|  | 40 |  | 
|  | 41 | func (afdo *afdo) props() []interface{} { | 
|  | 42 | return []interface{}{&afdo.Properties} | 
|  | 43 | } | 
|  | 44 |  | 
| Yi Kong | 9723e33 | 2023-12-04 14:52:53 +0900 | [diff] [blame] | 45 | func (afdo *afdo) begin(ctx BaseModuleContext) { | 
|  | 46 | // Disable on eng builds for faster build. | 
|  | 47 | if ctx.Config().Eng() { | 
|  | 48 | afdo.Properties.Afdo = false | 
|  | 49 | } | 
| Yi Kong | 3d9bed9 | 2024-08-05 15:12:57 +0900 | [diff] [blame] | 50 | // Disable for native coverage builds. | 
|  | 51 | if ctx.DeviceConfig().NativeCoverageEnabled() { | 
|  | 52 | afdo.Properties.Afdo = false | 
|  | 53 | } | 
| Yi Kong | 9723e33 | 2023-12-04 14:52:53 +0900 | [diff] [blame] | 54 | } | 
|  | 55 |  | 
| Vinh Tran | 44cb78c | 2023-03-09 22:07:19 -0500 | [diff] [blame] | 56 | // afdoEnabled returns true for binaries and shared libraries | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 57 | // that set afdo prop to True. | 
| Vinh Tran | 44cb78c | 2023-03-09 22:07:19 -0500 | [diff] [blame] | 58 | func (afdo *afdo) afdoEnabled() bool { | 
| Yabin Cui | 01c4456 | 2023-04-20 14:07:29 -0700 | [diff] [blame] | 59 | return afdo != nil && afdo.Properties.Afdo | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 60 | } | 
|  | 61 |  | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 62 | func (afdo *afdo) isAfdoCompile(ctx ModuleContext) bool { | 
|  | 63 | fdoProfilePath := getFdoProfilePathFromDep(ctx) | 
|  | 64 | return !ctx.Host() && (afdo.Properties.Afdo || afdo.Properties.AfdoDep) && (fdoProfilePath != "") | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | func getFdoProfilePathFromDep(ctx ModuleContext) string { | 
|  | 68 | fdoProfileDeps := ctx.GetDirectDepsWithTag(FdoProfileTag) | 
|  | 69 | if len(fdoProfileDeps) > 0 && fdoProfileDeps[0] != nil { | 
|  | 70 | if info, ok := android.OtherModuleProvider(ctx, fdoProfileDeps[0], FdoProfileProvider); ok { | 
|  | 71 | return info.Path.String() | 
|  | 72 | } | 
|  | 73 | } | 
|  | 74 | return "" | 
|  | 75 | } | 
|  | 76 |  | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 77 | func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags { | 
| Colin Cross | 15fa814 | 2024-02-07 15:09:08 -0800 | [diff] [blame] | 78 | if ctx.Host() { | 
|  | 79 | return flags | 
|  | 80 | } | 
|  | 81 |  | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 82 | if afdo.Properties.Afdo || afdo.Properties.AfdoDep { | 
| Yi Kong | 3d9bed9 | 2024-08-05 15:12:57 +0900 | [diff] [blame] | 83 | // Emit additional debug info for AutoFDO | 
|  | 84 | flags.Local.CFlags = append([]string{"-fdebug-info-for-profiling"}, flags.Local.CFlags...) | 
| Yabin Cui | 01c4456 | 2023-04-20 14:07:29 -0700 | [diff] [blame] | 85 | // We use `-funique-internal-linkage-names` to associate profiles to the right internal | 
|  | 86 | // functions. This option should be used before generating a profile. Because a profile | 
|  | 87 | // generated for a binary without unique names doesn't work well building a binary with | 
|  | 88 | // unique names (they have different internal function names). | 
|  | 89 | // To avoid a chicken-and-egg problem, we enable `-funique-internal-linkage-names` when | 
|  | 90 | // `afdo=true`, whether a profile exists or not. | 
|  | 91 | // The profile can take effect in three steps: | 
|  | 92 | // 1. Add `afdo: true` in Android.bp, and build the binary. | 
|  | 93 | // 2. Collect an AutoFDO profile for the binary. | 
|  | 94 | // 3. Make the profile searchable by the build system. So it's used the next time the binary | 
|  | 95 | //	  is built. | 
|  | 96 | flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...) | 
| Yi Kong | bc2d02a | 2023-10-16 16:57:53 +0900 | [diff] [blame] | 97 | // Flags for Flow Sensitive AutoFDO | 
| Yi Kong | b33ced0 | 2023-10-10 14:11:50 +0900 | [diff] [blame] | 98 | flags.Local.CFlags = append([]string{"-mllvm", "-enable-fs-discriminator=true"}, flags.Local.CFlags...) | 
| Yi Kong | bc2d02a | 2023-10-16 16:57:53 +0900 | [diff] [blame] | 99 | // TODO(b/266595187): Remove the following feature once it is enabled in LLVM by default. | 
|  | 100 | flags.Local.CFlags = append([]string{"-mllvm", "-improved-fs-discriminator=true"}, flags.Local.CFlags...) | 
| Yabin Cui | 01c4456 | 2023-04-20 14:07:29 -0700 | [diff] [blame] | 101 | } | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 102 | if fdoProfilePath := getFdoProfilePathFromDep(ctx); fdoProfilePath != "" { | 
| Ke-Yu Lu | 351d364 | 2024-02-06 02:15:03 +0000 | [diff] [blame] | 103 | // The flags are prepended to allow overriding. | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 104 | profileUseFlag := fmt.Sprintf(afdoFlagsFormat, fdoProfilePath) | 
| Ke-Yu Lu | 351d364 | 2024-02-06 02:15:03 +0000 | [diff] [blame] | 105 | flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...) | 
|  | 106 | flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...) | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 107 |  | 
| Ke-Yu Lu | 351d364 | 2024-02-06 02:15:03 +0000 | [diff] [blame] | 108 | // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt | 
|  | 109 | // if profileFile gets updated | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 110 | pathForSrc := android.PathForSource(ctx, fdoProfilePath) | 
| Ke-Yu Lu | 351d364 | 2024-02-06 02:15:03 +0000 | [diff] [blame] | 111 | flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc) | 
|  | 112 | flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc) | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 113 | } | 
|  | 114 |  | 
|  | 115 | return flags | 
|  | 116 | } | 
|  | 117 |  | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 118 | func (a *afdo) addDep(ctx android.BottomUpMutatorContext, fdoProfileTarget string) { | 
|  | 119 | if fdoProfileName, err := ctx.DeviceConfig().AfdoProfile(fdoProfileTarget); fdoProfileName != "" && err == nil { | 
|  | 120 | ctx.AddFarVariationDependencies( | 
|  | 121 | []blueprint.Variation{ | 
|  | 122 | {Mutator: "arch", Variation: ctx.Target().ArchVariation()}, | 
|  | 123 | {Mutator: "os", Variation: "android"}, | 
|  | 124 | }, | 
|  | 125 | FdoProfileTag, | 
|  | 126 | fdoProfileName) | 
| Colin Cross | d38feb0 | 2024-01-23 16:38:06 -0800 | [diff] [blame] | 127 | } | 
| Vinh Tran | 44cb78c | 2023-03-09 22:07:19 -0500 | [diff] [blame] | 128 | } | 
|  | 129 |  | 
| Colin Cross | d38feb0 | 2024-01-23 16:38:06 -0800 | [diff] [blame] | 130 | func afdoPropagateViaDepTag(tag blueprint.DependencyTag) bool { | 
|  | 131 | libTag, isLibTag := tag.(libraryDependencyTag) | 
|  | 132 | // Do not recurse down non-static dependencies | 
|  | 133 | if isLibTag { | 
|  | 134 | return libTag.static() | 
|  | 135 | } else { | 
|  | 136 | return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag | 
| Ke-Yu Lu | 0be9d60 | 2024-02-06 02:15:03 +0000 | [diff] [blame] | 137 | } | 
|  | 138 | } | 
|  | 139 |  | 
| Colin Cross | d38feb0 | 2024-01-23 16:38:06 -0800 | [diff] [blame] | 140 | // afdoTransitionMutator creates afdo variants of cc modules. | 
|  | 141 | type afdoTransitionMutator struct{} | 
|  | 142 |  | 
|  | 143 | func (a *afdoTransitionMutator) Split(ctx android.BaseModuleContext) []string { | 
|  | 144 | return []string{""} | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | func (a *afdoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { | 
|  | 148 | if ctx.Host() { | 
|  | 149 | return "" | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { | 
|  | 153 | if !afdoPropagateViaDepTag(ctx.DepTag()) { | 
|  | 154 | return "" | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | if sourceVariation != "" { | 
|  | 158 | return sourceVariation | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | if !m.afdo.afdoEnabled() { | 
|  | 162 | return "" | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | // TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but | 
|  | 166 | //  it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies. | 
|  | 167 | if m.static() { | 
|  | 168 | return "" | 
|  | 169 | } | 
|  | 170 |  | 
|  | 171 | return encodeTarget(ctx.Module().Name()) | 
|  | 172 | } | 
|  | 173 | return "" | 
|  | 174 | } | 
|  | 175 |  | 
|  | 176 | func (a *afdoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { | 
|  | 177 | if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { | 
|  | 178 | return incomingVariation | 
|  | 179 | } | 
|  | 180 | return "" | 
|  | 181 | } | 
|  | 182 |  | 
|  | 183 | func (a *afdoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { | 
| Colin Cross | d38feb0 | 2024-01-23 16:38:06 -0800 | [diff] [blame] | 184 | if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { | 
| Yi Kong | f885689 | 2024-07-03 02:02:23 +0900 | [diff] [blame] | 185 | if !m.Enabled(ctx) { | 
|  | 186 | return | 
|  | 187 | } | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 188 | if variation == "" { | 
|  | 189 | // The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO | 
|  | 190 | // variant of a dependency. | 
|  | 191 | if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() { | 
|  | 192 | m.afdo.addDep(ctx, ctx.ModuleName()) | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 193 | } | 
| Colin Cross | 3513fb1 | 2024-01-24 14:44:47 -0800 | [diff] [blame] | 194 | } else { | 
|  | 195 | // The non-empty variation is the AFDO variant of a dependency of a module that enabled AFDO | 
|  | 196 | // for itself. | 
|  | 197 | m.Properties.PreventInstall = true | 
|  | 198 | m.Properties.HideFromMake = true | 
|  | 199 | m.afdo.Properties.AfdoDep = true | 
|  | 200 | m.afdo.addDep(ctx, decodeTarget(variation)) | 
| Yi Kong | eb8efc9 | 2021-12-09 18:06:29 +0800 | [diff] [blame] | 201 | } | 
|  | 202 | } | 
|  | 203 | } | 
|  | 204 |  | 
|  | 205 | // Encode target name to variation name. | 
|  | 206 | func encodeTarget(target string) string { | 
|  | 207 | if target == "" { | 
|  | 208 | return "" | 
|  | 209 | } | 
|  | 210 | return "afdo-" + target | 
|  | 211 | } | 
|  | 212 |  | 
|  | 213 | // Decode target name from variation name. | 
|  | 214 | func decodeTarget(variation string) string { | 
|  | 215 | if variation == "" { | 
|  | 216 | return "" | 
|  | 217 | } | 
|  | 218 | return strings.TrimPrefix(variation, "afdo-") | 
|  | 219 | } |