blob: 0b662ebf43bd8a874c7fae6da58b1709ce5263c9 [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"
24 "github.com/google/blueprint/proptools"
Yi Kongeb8efc92021-12-09 18:06:29 +080025)
26
27var (
28 globalAfdoProfileProjects = []string{
29 "vendor/google_data/pgo_profile/sampling/",
30 "toolchain/pgo-profiles/sampling/",
31 }
32)
33
34var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
35
Yi Kong71198ac2022-02-10 15:08:36 +080036const afdoCFlagsFormat = "-funique-internal-linkage-names -fprofile-sample-accurate -fprofile-sample-use=%s"
Yi Kongeb8efc92021-12-09 18:06:29 +080037
Vinh Tran44cb78c2023-03-09 22:07:19 -050038// TODO(b/267229065): Remove getAfdoProfileProjects after reimplementing afdo support for rust
Yi Kongeb8efc92021-12-09 18:06:29 +080039func getAfdoProfileProjects(config android.DeviceConfig) []string {
40 return config.OnceStringSlice(afdoProfileProjectsConfigKey, func() []string {
Vinh Tran7a8362c2022-11-01 15:33:51 -040041 return globalAfdoProfileProjects
Yi Kongeb8efc92021-12-09 18:06:29 +080042 })
43}
44
Yi Kong46c6e592022-01-20 22:55:00 +080045func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
Yi Kongeb8efc92021-12-09 18:06:29 +080046 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
47}
48
Vinh Tran44cb78c2023-03-09 22:07:19 -050049type afdoRdep struct {
50 VariationName *string
51 ProfilePath *string
52}
53
Yi Kongeb8efc92021-12-09 18:06:29 +080054type AfdoProperties struct {
Alix40216ae2022-04-07 20:47:01 +000055 // Afdo allows developers self-service enroll for
56 // automatic feedback-directed optimization using profile data.
Yi Kongeb8efc92021-12-09 18:06:29 +080057 Afdo bool
58
Vinh Tran44cb78c2023-03-09 22:07:19 -050059 FdoProfilePath *string `blueprint:"mutated"`
60
61 AfdoRDeps []afdoRdep `blueprint:"mutated"`
Yi Kongeb8efc92021-12-09 18:06:29 +080062}
63
64type afdo struct {
65 Properties AfdoProperties
66}
67
68func (afdo *afdo) props() []interface{} {
69 return []interface{}{&afdo.Properties}
70}
71
Vinh Tran44cb78c2023-03-09 22:07:19 -050072// afdoEnabled returns true for binaries and shared libraries
73// that set afdo prop to True and there is a profile available
74func (afdo *afdo) afdoEnabled() bool {
75 return afdo != nil && afdo.Properties.Afdo && afdo.Properties.FdoProfilePath != nil
Yi Kongeb8efc92021-12-09 18:06:29 +080076}
77
78// Get list of profile file names, ordered by level of specialisation. For example:
Colin Crossd079e0b2022-08-16 10:27:33 -070079// 1. libfoo_arm64.afdo
80// 2. libfoo.afdo
81//
Yi Kongeb8efc92021-12-09 18:06:29 +080082// Add more specialisation as needed.
Vinh Tran44cb78c2023-03-09 22:07:19 -050083// TODO(b/267229065): Remove getProfileFiles after reimplementing afdo support for rust
Yi Kong46c6e592022-01-20 22:55:00 +080084func getProfileFiles(ctx android.BaseModuleContext, moduleName string) []string {
Yi Kongeb8efc92021-12-09 18:06:29 +080085 var files []string
86 files = append(files, moduleName+"_"+ctx.Arch().ArchType.String()+".afdo")
87 files = append(files, moduleName+".afdo")
88 return files
89}
90
Vinh Tran44cb78c2023-03-09 22:07:19 -050091// TODO(b/267229065): Remove GetAfdoProfileFile after reimplementing afdo support for rust
Yi Kong46c6e592022-01-20 22:55:00 +080092func (props *AfdoProperties) GetAfdoProfileFile(ctx android.BaseModuleContext, module string) android.OptionalPath {
Yi Kongeb8efc92021-12-09 18:06:29 +080093 // Test if the profile_file is present in any of the Afdo profile projects
94 for _, profileFile := range getProfileFiles(ctx, module) {
95 for _, profileProject := range getAfdoProfileProjects(ctx.DeviceConfig()) {
96 path := android.ExistentPathForSource(ctx, profileProject, profileFile)
97 if path.Valid() {
98 return path
99 }
100 }
101 }
102
103 // Record that this module's profile file is absent
104 missing := ctx.ModuleDir() + ":" + module
105 recordMissingAfdoProfileFile(ctx, missing)
106
107 return android.OptionalPathForPath(nil)
108}
109
Yi Kongeb8efc92021-12-09 18:06:29 +0800110func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
Vinh Tran44cb78c2023-03-09 22:07:19 -0500111 if path := afdo.Properties.FdoProfilePath; path != nil {
112 profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
113 flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
114 flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
115 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
Yi Kongeb8efc92021-12-09 18:06:29 +0800116
Vinh Tran44cb78c2023-03-09 22:07:19 -0500117 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
118 // if profileFile gets updated
119 pathForSrc := android.PathForSource(ctx, *path)
120 flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc)
121 flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc)
Yi Kongeb8efc92021-12-09 18:06:29 +0800122 }
123
124 return flags
125}
126
Vinh Tran44cb78c2023-03-09 22:07:19 -0500127func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
128 if ctx.Host() {
129 return
130 }
131
132 if ctx.static() && !ctx.staticBinary() {
133 return
134 }
135
136 if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
137 if fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()); fdoProfileName != nil && err == nil {
138 actx.AddFarVariationDependencies(
139 []blueprint.Variation{
140 {Mutator: "arch", Variation: actx.Target().ArchVariation()},
141 {Mutator: "os", Variation: "android"},
142 },
143 FdoProfileTag,
144 []string{*fdoProfileName}...,
145 )
146 }
147 }
148}
149
150// FdoProfileMutator reads the FdoProfileProvider from a direct dep with FdoProfileTag
151// assigns FdoProfileInfo.Path to the FdoProfilePath mutated property
152func (c *Module) FdoProfileMutator(ctx android.BottomUpMutatorContext) {
153 if !c.Enabled() {
154 return
155 }
156
157 ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
158 if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
159 info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
160 c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
161 }
162 })
163}
164
165var _ FdoProfileMutatorInterface = (*Module)(nil)
166
167// Propagate afdo requirements down from binaries and shared libraries
Yi Kongeb8efc92021-12-09 18:06:29 +0800168func afdoDepsMutator(mctx android.TopDownMutatorContext) {
Vinh Tran44cb78c2023-03-09 22:07:19 -0500169 if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
170 if path := m.afdo.Properties.FdoProfilePath; path != nil {
171 mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
172 tag := mctx.OtherModuleDependencyTag(dep)
173 libTag, isLibTag := tag.(libraryDependencyTag)
Yi Kongeb8efc92021-12-09 18:06:29 +0800174
Vinh Tran44cb78c2023-03-09 22:07:19 -0500175 // Do not recurse down non-static dependencies
176 if isLibTag {
177 if !libTag.static() {
178 return false
179 }
180 } else {
181 if tag != objDepTag && tag != reuseObjTag {
182 return false
183 }
Yi Kongeb8efc92021-12-09 18:06:29 +0800184 }
Vinh Tran44cb78c2023-03-09 22:07:19 -0500185
186 if dep, ok := dep.(*Module); ok {
187 dep.afdo.Properties.AfdoRDeps = append(
188 dep.afdo.Properties.AfdoRDeps,
189 afdoRdep{
190 VariationName: proptools.StringPtr(encodeTarget(m.Name())),
191 ProfilePath: path,
192 },
193 )
Yi Kongeb8efc92021-12-09 18:06:29 +0800194 }
Yi Kongeb8efc92021-12-09 18:06:29 +0800195
Vinh Tran44cb78c2023-03-09 22:07:19 -0500196 return true
197 })
198 }
Yi Kongeb8efc92021-12-09 18:06:29 +0800199 }
200}
201
202// Create afdo variants for modules that need them
203func afdoMutator(mctx android.BottomUpMutatorContext) {
204 if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
Vinh Tran44cb78c2023-03-09 22:07:19 -0500205 if !m.static() && m.afdo.Properties.Afdo && m.afdo.Properties.FdoProfilePath != nil {
206 mctx.SetDependencyVariation(encodeTarget(m.Name()))
207 return
Yi Kongeb8efc92021-12-09 18:06:29 +0800208 }
209
210 variationNames := []string{""}
Vinh Tran44cb78c2023-03-09 22:07:19 -0500211
212 variantNameToProfilePath := make(map[string]*string)
213
214 for _, afdoRDep := range m.afdo.Properties.AfdoRDeps {
215 variantName := *afdoRDep.VariationName
216 // An rdep can be set twice in AfdoRDeps because there can be
217 // more than one path from an afdo-enabled module to
218 // a static dep such as
219 // afdo_enabled_foo -> static_bar ----> static_baz
220 // \ ^
221 // ----------------------|
222 // We only need to create one variant per unique rdep
223 if variantNameToProfilePath[variantName] == nil {
224 variationNames = append(variationNames, variantName)
225 variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
226 }
Yi Kongeb8efc92021-12-09 18:06:29 +0800227 }
Vinh Tran44cb78c2023-03-09 22:07:19 -0500228
Yi Kongeb8efc92021-12-09 18:06:29 +0800229 if len(variationNames) > 1 {
230 modules := mctx.CreateVariations(variationNames...)
231 for i, name := range variationNames {
232 if name == "" {
233 continue
234 }
235 variation := modules[i].(*Module)
236 variation.Properties.PreventInstall = true
237 variation.Properties.HideFromMake = true
Vinh Tran44cb78c2023-03-09 22:07:19 -0500238 variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
Yi Kongeb8efc92021-12-09 18:06:29 +0800239 }
240 }
241 }
242}
243
244// Encode target name to variation name.
245func encodeTarget(target string) string {
246 if target == "" {
247 return ""
248 }
249 return "afdo-" + target
250}
251
252// Decode target name from variation name.
253func decodeTarget(variation string) string {
254 if variation == "" {
255 return ""
256 }
257 return strings.TrimPrefix(variation, "afdo-")
258}