blob: 463e2e6230525abead8c18c05dd28933197d111d [file] [log] [blame]
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -07001// Copyright 2017 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"
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -080019 "path/filepath"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070020 "strings"
21
Yi Kongca610d22018-04-24 10:42:02 -070022 "github.com/google/blueprint/proptools"
23
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070024 "android/soong/android"
25)
26
27var (
28 // Add flags to ignore warnings that profiles are old or missing for
Pirama Arumuga Nainar3a254052019-06-14 09:54:23 -070029 // some functions.
Yi Kong69c1ed92019-03-21 14:28:13 -070030 profileUseOtherFlags = []string{
31 "-Wno-backend-plugin",
Yi Kong69c1ed92019-03-21 14:28:13 -070032 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070033
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080034 globalPgoProfileProjects = []string{
Yi Kong88b94ea2022-04-07 23:54:28 +080035 "toolchain/pgo-profiles/pgo",
36 "vendor/google_data/pgo_profile/pgo",
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080037 }
38)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070039
Colin Cross571cccf2019-02-04 11:22:08 -080040var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
41
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070042const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070043const profileUseInstrumentFormat = "-fprofile-use=%s"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070044
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080045func getPgoProfileProjects(config android.DeviceConfig) []string {
46 return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
47 return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...)
48 })
49}
50
Yi Kong7e53c572018-02-14 18:16:12 +080051func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
Colin Cross571cccf2019-02-04 11:22:08 -080052 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -080053}
54
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070055type PgoProperties struct {
56 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070057 Instrumentation *bool
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070058 Profile_file *string `android:"arch_variant"`
59 Benchmarks []string
60 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080061 // Additional compiler flags to use when building this module
Yi Kongfe841862022-06-07 15:23:08 +080062 // for profiling.
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080063 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070064 } `android:"arch_variant"`
65
66 PgoPresent bool `blueprint:"mutated"`
67 ShouldProfileModule bool `blueprint:"mutated"`
Yi Kong7e53c572018-02-14 18:16:12 +080068 PgoCompile bool `blueprint:"mutated"`
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -070069 PgoInstrLink bool `blueprint:"mutated"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070070}
71
72type pgo struct {
73 Properties PgoProperties
74}
75
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070076func (props *PgoProperties) isInstrumentation() bool {
77 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
78}
79
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070080func (pgo *pgo) props() []interface{} {
81 return []interface{}{&pgo.Properties}
82}
83
Yi Kongceb5b762020-03-20 15:22:27 +080084func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -070085 // Add to C flags iff PGO is explicitly enabled for this module.
86 if props.ShouldProfileModule {
87 flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
88 flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
89 }
90 flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag)
Yi Kongceb5b762020-03-20 15:22:27 +080091 return flags
92}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070093
Yi Kong7e53c572018-02-14 18:16:12 +080094func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
Jaewoong Jung18aefc12020-12-21 09:11:10 -080095 profileFile := *props.Pgo.Profile_file
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -080096
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080097 // Test if the profile_file is present in any of the PGO profile projects
98 for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -080099 // Bug: http://b/74395273 If the profile_file is unavailable,
100 // use a versioned file named
101 // <profile_file>.<arbitrary-version> when available. This
102 // works around an issue where ccache serves stale cache
103 // entries when the profile file has changed.
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800104 globPattern := filepath.Join(profileProject, profileFile+".*")
105 versionedProfiles, err := ctx.GlobWithDeps(globPattern, nil)
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800106 if err != nil {
107 ctx.ModuleErrorf("glob: %s", err.Error())
108 }
109
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800110 path := android.ExistentPathForSource(ctx, profileProject, profileFile)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800111 if path.Valid() {
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800112 if len(versionedProfiles) != 0 {
113 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profileFile)+", "+strings.Join(versionedProfiles, ", "))
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800114 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800115 return path
116 }
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800117
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800118 if len(versionedProfiles) > 1 {
119 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versionedProfiles, ", "))
120 } else if len(versionedProfiles) == 1 {
121 return android.OptionalPathForPath(android.PathForSource(ctx, versionedProfiles[0]))
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800122 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800123 }
124
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -0800125 // Record that this module's profile file is absent
126 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
127 recordMissingProfileFile(ctx, missing)
128
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800129 return android.OptionalPathForPath(nil)
130}
131
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700132func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
Yi Kongfe841862022-06-07 15:23:08 +0800133 flags := []string{fmt.Sprintf(profileUseInstrumentFormat, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700134 flags = append(flags, profileUseOtherFlags...)
135 return flags
136}
137
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700138func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800139 // Return if 'pgo' property is not present in this module.
140 if !props.PgoPresent {
141 return flags
142 }
143
Yi Kongca610d22018-04-24 10:42:02 -0700144 if props.PgoCompile {
145 profileFile := props.getPgoProfileFile(ctx)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800146 profileFilePath := profileFile.Path()
147 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700148
Colin Cross4af21ed2019-11-04 09:37:55 -0800149 flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlags...)
150 flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlags...)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700151
152 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
153 // if profileFile gets updated
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800154 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
155 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700156 }
157 return flags
158}
159
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700160func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700161 isInstrumentation := props.isInstrumentation()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700162
Yi Kongfe841862022-06-07 15:23:08 +0800163 profileKindPresent := isInstrumentation
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700164 filePresent := props.Pgo.Profile_file != nil
165 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
166
167 // If all three properties are absent, PGO is OFF for this module
168 if !profileKindPresent && !filePresent && !benchmarksPresent {
169 return false
170 }
171
Yi Kong84803c52020-07-21 15:38:23 +0800172 // profileKindPresent and filePresent are mandatory properties.
173 if !profileKindPresent || !filePresent {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700174 var missing []string
175 if !profileKindPresent {
Yi Kongfe841862022-06-07 15:23:08 +0800176 missing = append(missing, "profile kind")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700177 }
178 if !filePresent {
179 missing = append(missing, "profile_file property")
180 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700181 missingProps := strings.Join(missing, ", ")
182 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
183 }
184
Yi Kong84803c52020-07-21 15:38:23 +0800185 // Benchmark property is mandatory for instrumentation PGO.
186 if isInstrumentation && !benchmarksPresent {
187 ctx.ModuleErrorf("Instrumentation PGO specification is missing benchmark property")
188 }
189
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700190 return true
191}
192
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700193func (pgo *pgo) begin(ctx BaseModuleContext) {
194 // TODO Evaluate if we need to support PGO for host modules
195 if ctx.Host() {
196 return
197 }
198
199 // Check if PGO is needed for this module
200 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
201
202 if !pgo.Properties.PgoPresent {
203 return
204 }
205
206 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800207 // and includes 'all', 'ALL' or a benchmark listed for this module.
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700208 //
209 // TODO Validate that each benchmark instruments at least one module
210 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800211 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700212 pgoBenchmarksMap := make(map[string]bool)
213 for _, b := range strings.Split(pgoBenchmarks, ",") {
214 pgoBenchmarksMap[b] = true
215 }
216
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800217 if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
218 pgo.Properties.ShouldProfileModule = true
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700219 pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800220 } else {
221 for _, b := range pgo.Properties.Pgo.Benchmarks {
222 if pgoBenchmarksMap[b] == true {
223 pgo.Properties.ShouldProfileModule = true
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700224 pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800225 break
226 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700227 }
228 }
Yi Kong7e53c572018-02-14 18:16:12 +0800229
Pirama Arumuga Nainar807d49b2020-02-12 13:57:37 -0800230 // PGO profile use is not feasible for a Clang coverage build because
231 // -fprofile-use and -fprofile-instr-generate are incompatible.
232 if ctx.DeviceConfig().ClangCoverageEnabled() {
233 return
234 }
235
Yi Kongca610d22018-04-24 10:42:02 -0700236 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
237 proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
Yi Kong7e53c572018-02-14 18:16:12 +0800238 if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
239 pgo.Properties.PgoCompile = true
240 }
241 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700242}
243
244func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
245 if ctx.Host() {
246 return flags
247 }
248
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700249 // Deduce PgoInstrLink property i.e. whether this module needs to be
250 // linked with profile-generation flags. Here, we're setting it if any
251 // dependency needs PGO instrumentation. It is initially set in
252 // begin() if PGO is directly enabled for this module.
253 if ctx.static() && !ctx.staticBinary() {
254 // For static libraries, check if any whole_static_libs are
255 // linked with profile generation
256 ctx.VisitDirectDeps(func(m android.Module) {
257 if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
258 if depTag.static() && depTag.wholeStatic {
259 if cc, ok := m.(*Module); ok {
260 if cc.pgo.Properties.PgoInstrLink {
261 pgo.Properties.PgoInstrLink = true
262 }
263 }
264 }
265 }
266 })
267 } else {
268 // For executables and shared libraries, check all static dependencies.
269 ctx.VisitDirectDeps(func(m android.Module) {
270 if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
271 if depTag.static() {
272 if cc, ok := m.(*Module); ok {
273 if cc.pgo.Properties.PgoInstrLink {
274 pgo.Properties.PgoInstrLink = true
275 }
276 }
277 }
278 }
279 })
280 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700281
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700282 props := pgo.Properties
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700283 // Add flags to profile this module based on its profile_kind
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700284 if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink {
Yi Konga575ff32020-07-22 01:41:58 +0800285 // Instrumentation PGO use and gather flags cannot coexist.
Pirama Arumuga Nainarfe1da752020-09-02 17:44:06 +0000286 return props.addInstrumentationProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700287 }
288
Colin Cross6510f912017-11-29 00:27:14 -0800289 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainarfe1da752020-09-02 17:44:06 +0000290 flags = props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700291 }
292
293 return flags
294}