blob: 6cc17467d35d7edf198a0185fb6dd5f57253cbc6 [file] [log] [blame]
Yi Kongeb8efc92021-12-09 18:06:29 +08001// 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
Yi Kongeb8efc92021-12-09 18:06:29 +080021 "android/soong/android"
Vinh Tran44cb78c2023-03-09 22:07:19 -050022
23 "github.com/google/blueprint"
Ke-Yu Lu351d3642024-02-06 02:15:03 +000024 "github.com/google/blueprint/proptools"
Yi Kongeb8efc92021-12-09 18:06:29 +080025)
26
Vinh Tran056effb2023-06-27 14:03:25 +000027// This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering
Yi Kong0880a822023-11-14 23:49:40 +000028const afdoFlagsFormat = "-fprofile-sample-use=%s -fprofile-sample-accurate"
Yi Kongeb8efc92021-12-09 18:06:29 +080029
Ke-Yu Lu0be9d602024-02-06 02:15:03 +000030func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
31 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
32}
33
34type afdoRdep struct {
35 VariationName *string
36 ProfilePath *string
37}
38
Yi Kongeb8efc92021-12-09 18:06:29 +080039type AfdoProperties struct {
Alix40216ae2022-04-07 20:47:01 +000040 // Afdo allows developers self-service enroll for
41 // automatic feedback-directed optimization using profile data.
Yi Kongeb8efc92021-12-09 18:06:29 +080042 Afdo bool
43
Ke-Yu Lu351d3642024-02-06 02:15:03 +000044 FdoProfilePath *string `blueprint:"mutated"`
Ke-Yu Lu0be9d602024-02-06 02:15:03 +000045
46 AfdoRDeps []afdoRdep `blueprint:"mutated"`
Yi Kongeb8efc92021-12-09 18:06:29 +080047}
48
49type afdo struct {
50 Properties AfdoProperties
51}
52
53func (afdo *afdo) props() []interface{} {
54 return []interface{}{&afdo.Properties}
55}
56
Yi Kong9723e332023-12-04 14:52:53 +090057func (afdo *afdo) begin(ctx BaseModuleContext) {
58 // Disable on eng builds for faster build.
59 if ctx.Config().Eng() {
60 afdo.Properties.Afdo = false
61 }
62}
63
Vinh Tran44cb78c2023-03-09 22:07:19 -050064// afdoEnabled returns true for binaries and shared libraries
65// that set afdo prop to True and there is a profile available
66func (afdo *afdo) afdoEnabled() bool {
Yabin Cui01c44562023-04-20 14:07:29 -070067 return afdo != nil && afdo.Properties.Afdo
Yi Kongeb8efc92021-12-09 18:06:29 +080068}
69
Yi Kongeb8efc92021-12-09 18:06:29 +080070func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
Colin Cross15fa8142024-02-07 15:09:08 -080071 if ctx.Host() {
72 return flags
73 }
74
Ke-Yu Lu351d3642024-02-06 02:15:03 +000075 if afdo.Properties.Afdo {
Yabin Cui01c44562023-04-20 14:07:29 -070076 // We use `-funique-internal-linkage-names` to associate profiles to the right internal
77 // functions. This option should be used before generating a profile. Because a profile
78 // generated for a binary without unique names doesn't work well building a binary with
79 // unique names (they have different internal function names).
80 // To avoid a chicken-and-egg problem, we enable `-funique-internal-linkage-names` when
81 // `afdo=true`, whether a profile exists or not.
82 // The profile can take effect in three steps:
83 // 1. Add `afdo: true` in Android.bp, and build the binary.
84 // 2. Collect an AutoFDO profile for the binary.
85 // 3. Make the profile searchable by the build system. So it's used the next time the binary
86 // is built.
87 flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...)
Yi Kongbc2d02a2023-10-16 16:57:53 +090088 // Flags for Flow Sensitive AutoFDO
Yi Kongb33ced02023-10-10 14:11:50 +090089 flags.Local.CFlags = append([]string{"-mllvm", "-enable-fs-discriminator=true"}, flags.Local.CFlags...)
Yi Kongbc2d02a2023-10-16 16:57:53 +090090 // TODO(b/266595187): Remove the following feature once it is enabled in LLVM by default.
91 flags.Local.CFlags = append([]string{"-mllvm", "-improved-fs-discriminator=true"}, flags.Local.CFlags...)
Yabin Cui01c44562023-04-20 14:07:29 -070092 }
Ke-Yu Lu351d3642024-02-06 02:15:03 +000093 if path := afdo.Properties.FdoProfilePath; path != nil {
94 // The flags are prepended to allow overriding.
95 profileUseFlag := fmt.Sprintf(afdoFlagsFormat, *path)
96 flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...)
97 flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...)
Yi Kongeb8efc92021-12-09 18:06:29 +080098
Ke-Yu Lu351d3642024-02-06 02:15:03 +000099 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
100 // if profileFile gets updated
101 pathForSrc := android.PathForSource(ctx, *path)
102 flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc)
103 flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc)
Yi Kongeb8efc92021-12-09 18:06:29 +0800104 }
105
106 return flags
107}
108
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000109func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
110 if ctx.Host() {
111 return
112 }
113
114 if ctx.static() && !ctx.staticBinary() {
115 return
116 }
117
118 if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
119 if fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()); fdoProfileName != nil && err == nil {
120 actx.AddFarVariationDependencies(
121 []blueprint.Variation{
122 {Mutator: "arch", Variation: actx.Target().ArchVariation()},
123 {Mutator: "os", Variation: "android"},
124 },
125 FdoProfileTag,
126 []string{*fdoProfileName}...,
127 )
128 }
129 }
130}
131
Ke-Yu Lu351d3642024-02-06 02:15:03 +0000132// FdoProfileMutator reads the FdoProfileProvider from a direct dep with FdoProfileTag
133// assigns FdoProfileInfo.Path to the FdoProfilePath mutated property
134func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
135 if !c.Enabled() {
136 return
137 }
138
139 if !c.afdo.afdoEnabled() {
140 return
141 }
142
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000143 ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
144 if info, ok := android.OtherModuleProvider(ctx, m, FdoProfileProvider); ok {
145 c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
Ke-Yu Lu351d3642024-02-06 02:15:03 +0000146 }
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000147 })
Vinh Tran44cb78c2023-03-09 22:07:19 -0500148}
149
Ke-Yu Lu351d3642024-02-06 02:15:03 +0000150var _ FdoProfileMutatorInterface = (*Module)(nil)
151
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000152// Propagate afdo requirements down from binaries and shared libraries
153func afdoDepsMutator(mctx android.TopDownMutatorContext) {
Colin Cross15fa8142024-02-07 15:09:08 -0800154 if mctx.Host() {
155 return
156 }
157
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000158 if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
159 path := m.afdo.Properties.FdoProfilePath
160 mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
161 tag := mctx.OtherModuleDependencyTag(dep)
162 libTag, isLibTag := tag.(libraryDependencyTag)
Yi Kongeb8efc92021-12-09 18:06:29 +0800163
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000164 // Do not recurse down non-static dependencies
165 if isLibTag {
166 if !libTag.static() {
167 return false
Ke-Yu Lu351d3642024-02-06 02:15:03 +0000168 }
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000169 } else {
170 if tag != objDepTag && tag != reuseObjTag {
171 return false
172 }
173 }
174
175 if dep, ok := dep.(*Module); ok {
176 dep.afdo.Properties.AfdoRDeps = append(
177 dep.afdo.Properties.AfdoRDeps,
178 afdoRdep{
179 VariationName: proptools.StringPtr(encodeTarget(m.Name())),
180 ProfilePath: path,
181 },
182 )
183 }
184
185 return true
186 })
187 }
188}
189
190// Create afdo variants for modules that need them
191func afdoMutator(mctx android.BottomUpMutatorContext) {
Colin Cross15fa8142024-02-07 15:09:08 -0800192 if mctx.Host() {
193 return
194 }
195
Ke-Yu Lu0be9d602024-02-06 02:15:03 +0000196 if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
197 if !m.static() && m.afdo.Properties.Afdo {
198 mctx.SetDependencyVariation(encodeTarget(m.Name()))
199 return
200 }
201
202 variationNames := []string{""}
203
204 variantNameToProfilePath := make(map[string]*string)
205
206 for _, afdoRDep := range m.afdo.Properties.AfdoRDeps {
207 variantName := *afdoRDep.VariationName
208 // An rdep can be set twice in AfdoRDeps because there can be
209 // more than one path from an afdo-enabled module to
210 // a static dep such as
211 // afdo_enabled_foo -> static_bar ----> static_baz
212 // \ ^
213 // ----------------------|
214 // We only need to create one variant per unique rdep
215 if _, exists := variantNameToProfilePath[variantName]; !exists {
216 variationNames = append(variationNames, variantName)
217 variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
218 }
219 }
220
221 if len(variationNames) > 1 {
222 modules := mctx.CreateVariations(variationNames...)
223 for i, name := range variationNames {
224 if name == "" {
225 continue
226 }
227 variation := modules[i].(*Module)
228 variation.Properties.PreventInstall = true
229 variation.Properties.HideFromMake = true
230 variation.afdo.Properties.Afdo = true
231 variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
Yi Kongeb8efc92021-12-09 18:06:29 +0800232 }
Yi Kongeb8efc92021-12-09 18:06:29 +0800233 }
234 }
235}
236
237// Encode target name to variation name.
238func encodeTarget(target string) string {
239 if target == "" {
240 return ""
241 }
242 return "afdo-" + target
243}
244
245// Decode target name from variation name.
246func decodeTarget(variation string) string {
247 if variation == "" {
248 return ""
249 }
250 return strings.TrimPrefix(variation, "afdo-")
251}