blob: 66e97328458e076ab74845e5be0b1292be513def [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
21 "github.com/google/blueprint/proptools"
22
23 "android/soong/android"
24)
25
26var (
27 globalAfdoProfileProjects = []string{
28 "vendor/google_data/pgo_profile/sampling/",
29 "toolchain/pgo-profiles/sampling/",
30 }
31)
32
33var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
34
Yi Kong71198ac2022-02-10 15:08:36 +080035const afdoCFlagsFormat = "-funique-internal-linkage-names -fprofile-sample-accurate -fprofile-sample-use=%s"
Yi Kongeb8efc92021-12-09 18:06:29 +080036
37func getAfdoProfileProjects(config android.DeviceConfig) []string {
38 return config.OnceStringSlice(afdoProfileProjectsConfigKey, func() []string {
39 return append(globalAfdoProfileProjects, config.AfdoAdditionalProfileDirs()...)
40 })
41}
42
Yi Kong46c6e592022-01-20 22:55:00 +080043func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
Yi Kongeb8efc92021-12-09 18:06:29 +080044 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
45}
46
47type AfdoProperties struct {
Alix40216ae2022-04-07 20:47:01 +000048 // Afdo allows developers self-service enroll for
49 // automatic feedback-directed optimization using profile data.
Yi Kongeb8efc92021-12-09 18:06:29 +080050 Afdo bool
51
52 AfdoTarget *string `blueprint:"mutated"`
53 AfdoDeps []string `blueprint:"mutated"`
54}
55
56type afdo struct {
57 Properties AfdoProperties
58}
59
60func (afdo *afdo) props() []interface{} {
61 return []interface{}{&afdo.Properties}
62}
63
64func (afdo *afdo) AfdoEnabled() bool {
65 return afdo != nil && afdo.Properties.Afdo && afdo.Properties.AfdoTarget != nil
66}
67
68// Get list of profile file names, ordered by level of specialisation. For example:
69// 1. libfoo_arm64.afdo
70// 2. libfoo.afdo
71// Add more specialisation as needed.
Yi Kong46c6e592022-01-20 22:55:00 +080072func getProfileFiles(ctx android.BaseModuleContext, moduleName string) []string {
Yi Kongeb8efc92021-12-09 18:06:29 +080073 var files []string
74 files = append(files, moduleName+"_"+ctx.Arch().ArchType.String()+".afdo")
75 files = append(files, moduleName+".afdo")
76 return files
77}
78
Yi Kong46c6e592022-01-20 22:55:00 +080079func (props *AfdoProperties) GetAfdoProfileFile(ctx android.BaseModuleContext, module string) android.OptionalPath {
Yi Kongeb8efc92021-12-09 18:06:29 +080080 // Test if the profile_file is present in any of the Afdo profile projects
81 for _, profileFile := range getProfileFiles(ctx, module) {
82 for _, profileProject := range getAfdoProfileProjects(ctx.DeviceConfig()) {
83 path := android.ExistentPathForSource(ctx, profileProject, profileFile)
84 if path.Valid() {
85 return path
86 }
87 }
88 }
89
90 // Record that this module's profile file is absent
91 missing := ctx.ModuleDir() + ":" + module
92 recordMissingAfdoProfileFile(ctx, missing)
93
94 return android.OptionalPathForPath(nil)
95}
96
97func (afdo *afdo) begin(ctx BaseModuleContext) {
Yi Kong88e632e2022-01-25 03:12:48 +080098 if ctx.Host() {
99 return
100 }
101 if ctx.static() && !ctx.staticBinary() {
102 return
103 }
104 if afdo.Properties.Afdo {
Yi Kongeb8efc92021-12-09 18:06:29 +0800105 module := ctx.ModuleName()
Yi Kong46c6e592022-01-20 22:55:00 +0800106 if afdo.Properties.GetAfdoProfileFile(ctx, module).Valid() {
Yi Kongeb8efc92021-12-09 18:06:29 +0800107 afdo.Properties.AfdoTarget = proptools.StringPtr(module)
108 }
109 }
110}
111
112func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
113 if profile := afdo.Properties.AfdoTarget; profile != nil {
Yi Kong46c6e592022-01-20 22:55:00 +0800114 if profileFile := afdo.Properties.GetAfdoProfileFile(ctx, *profile); profileFile.Valid() {
Yi Kongeb8efc92021-12-09 18:06:29 +0800115 profileFilePath := profileFile.Path()
116
117 profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, profileFile)
118 flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
119 flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
120 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
121
122 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
123 // if profileFile gets updated
124 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
125 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
126 }
127 }
128
129 return flags
130}
131
132// Propagate afdo requirements down from binaries
133func afdoDepsMutator(mctx android.TopDownMutatorContext) {
134 if m, ok := mctx.Module().(*Module); ok && m.afdo.AfdoEnabled() {
135 afdoTarget := *m.afdo.Properties.AfdoTarget
136 mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
137 tag := mctx.OtherModuleDependencyTag(dep)
138 libTag, isLibTag := tag.(libraryDependencyTag)
139
140 // Do not recurse down non-static dependencies
141 if isLibTag {
142 if !libTag.static() {
143 return false
144 }
145 } else {
146 if tag != objDepTag && tag != reuseObjTag {
147 return false
148 }
149 }
150
151 if dep, ok := dep.(*Module); ok {
152 dep.afdo.Properties.AfdoDeps = append(dep.afdo.Properties.AfdoDeps, afdoTarget)
153 }
154
155 return true
156 })
157 }
158}
159
160// Create afdo variants for modules that need them
161func afdoMutator(mctx android.BottomUpMutatorContext) {
162 if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
163 if m.afdo.AfdoEnabled() && !m.static() {
164 afdoTarget := *m.afdo.Properties.AfdoTarget
165 mctx.SetDependencyVariation(encodeTarget(afdoTarget))
166 }
167
168 variationNames := []string{""}
169 afdoDeps := android.FirstUniqueStrings(m.afdo.Properties.AfdoDeps)
170 for _, dep := range afdoDeps {
171 variationNames = append(variationNames, encodeTarget(dep))
172 }
173 if len(variationNames) > 1 {
174 modules := mctx.CreateVariations(variationNames...)
175 for i, name := range variationNames {
176 if name == "" {
177 continue
178 }
179 variation := modules[i].(*Module)
180 variation.Properties.PreventInstall = true
181 variation.Properties.HideFromMake = true
182 variation.afdo.Properties.AfdoTarget = proptools.StringPtr(decodeTarget(name))
183 }
184 }
185 }
186}
187
188// Encode target name to variation name.
189func encodeTarget(target string) string {
190 if target == "" {
191 return ""
192 }
193 return "afdo-" + target
194}
195
196// Decode target name from variation name.
197func decodeTarget(variation string) string {
198 if variation == "" {
199 return ""
200 }
201 return strings.TrimPrefix(variation, "afdo-")
202}