blob: d36f4afcfa07c687bd934d78b855f257de45b56c [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 {
Vinh Tran7a8362c2022-11-01 15:33:51 -040039 return globalAfdoProfileProjects
Yi Kongeb8efc92021-12-09 18:06:29 +080040 })
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:
Colin Crossd079e0b2022-08-16 10:27:33 -070069// 1. libfoo_arm64.afdo
70// 2. libfoo.afdo
71//
Yi Kongeb8efc92021-12-09 18:06:29 +080072// Add more specialisation as needed.
Yi Kong46c6e592022-01-20 22:55:00 +080073func getProfileFiles(ctx android.BaseModuleContext, moduleName string) []string {
Yi Kongeb8efc92021-12-09 18:06:29 +080074 var files []string
75 files = append(files, moduleName+"_"+ctx.Arch().ArchType.String()+".afdo")
76 files = append(files, moduleName+".afdo")
77 return files
78}
79
Yi Kong46c6e592022-01-20 22:55:00 +080080func (props *AfdoProperties) GetAfdoProfileFile(ctx android.BaseModuleContext, module string) android.OptionalPath {
Yi Kongeb8efc92021-12-09 18:06:29 +080081 // Test if the profile_file is present in any of the Afdo profile projects
82 for _, profileFile := range getProfileFiles(ctx, module) {
83 for _, profileProject := range getAfdoProfileProjects(ctx.DeviceConfig()) {
84 path := android.ExistentPathForSource(ctx, profileProject, profileFile)
85 if path.Valid() {
86 return path
87 }
88 }
89 }
90
91 // Record that this module's profile file is absent
92 missing := ctx.ModuleDir() + ":" + module
93 recordMissingAfdoProfileFile(ctx, missing)
94
95 return android.OptionalPathForPath(nil)
96}
97
98func (afdo *afdo) begin(ctx BaseModuleContext) {
Yi Kong88e632e2022-01-25 03:12:48 +080099 if ctx.Host() {
100 return
101 }
102 if ctx.static() && !ctx.staticBinary() {
103 return
104 }
105 if afdo.Properties.Afdo {
Yi Kongeb8efc92021-12-09 18:06:29 +0800106 module := ctx.ModuleName()
Yi Kong46c6e592022-01-20 22:55:00 +0800107 if afdo.Properties.GetAfdoProfileFile(ctx, module).Valid() {
Yi Kongeb8efc92021-12-09 18:06:29 +0800108 afdo.Properties.AfdoTarget = proptools.StringPtr(module)
109 }
110 }
111}
112
113func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
114 if profile := afdo.Properties.AfdoTarget; profile != nil {
Yi Kong46c6e592022-01-20 22:55:00 +0800115 if profileFile := afdo.Properties.GetAfdoProfileFile(ctx, *profile); profileFile.Valid() {
Yi Kongeb8efc92021-12-09 18:06:29 +0800116 profileFilePath := profileFile.Path()
117
118 profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, profileFile)
119 flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
120 flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
121 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
122
123 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
124 // if profileFile gets updated
125 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
126 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
127 }
128 }
129
130 return flags
131}
132
133// Propagate afdo requirements down from binaries
134func afdoDepsMutator(mctx android.TopDownMutatorContext) {
135 if m, ok := mctx.Module().(*Module); ok && m.afdo.AfdoEnabled() {
136 afdoTarget := *m.afdo.Properties.AfdoTarget
137 mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
138 tag := mctx.OtherModuleDependencyTag(dep)
139 libTag, isLibTag := tag.(libraryDependencyTag)
140
141 // Do not recurse down non-static dependencies
142 if isLibTag {
143 if !libTag.static() {
144 return false
145 }
146 } else {
147 if tag != objDepTag && tag != reuseObjTag {
148 return false
149 }
150 }
151
152 if dep, ok := dep.(*Module); ok {
153 dep.afdo.Properties.AfdoDeps = append(dep.afdo.Properties.AfdoDeps, afdoTarget)
154 }
155
156 return true
157 })
158 }
159}
160
161// Create afdo variants for modules that need them
162func afdoMutator(mctx android.BottomUpMutatorContext) {
163 if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
164 if m.afdo.AfdoEnabled() && !m.static() {
165 afdoTarget := *m.afdo.Properties.AfdoTarget
166 mctx.SetDependencyVariation(encodeTarget(afdoTarget))
167 }
168
169 variationNames := []string{""}
170 afdoDeps := android.FirstUniqueStrings(m.afdo.Properties.AfdoDeps)
171 for _, dep := range afdoDeps {
172 variationNames = append(variationNames, encodeTarget(dep))
173 }
174 if len(variationNames) > 1 {
175 modules := mctx.CreateVariations(variationNames...)
176 for i, name := range variationNames {
177 if name == "" {
178 continue
179 }
180 variation := modules[i].(*Module)
181 variation.Properties.PreventInstall = true
182 variation.Properties.HideFromMake = true
183 variation.afdo.Properties.AfdoTarget = proptools.StringPtr(decodeTarget(name))
184 }
185 }
186 }
187}
188
189// Encode target name to variation name.
190func encodeTarget(target string) string {
191 if target == "" {
192 return ""
193 }
194 return "afdo-" + target
195}
196
197// Decode target name from variation name.
198func decodeTarget(variation string) string {
199 if variation == "" {
200 return ""
201 }
202 return strings.TrimPrefix(variation, "afdo-")
203}