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