blob: ada694b06a0dd2d8dacbbbdd03b00cbeaacb3593 [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"
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070025 "android/soong/cc/config"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070026)
27
28var (
29 // Add flags to ignore warnings that profiles are old or missing for
Pirama Arumuga Nainar3a254052019-06-14 09:54:23 -070030 // some functions.
Yi Kong69c1ed92019-03-21 14:28:13 -070031 profileUseOtherFlags = []string{
32 "-Wno-backend-plugin",
Yi Kong69c1ed92019-03-21 14:28:13 -070033 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070034
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080035 globalPgoProfileProjects = []string{
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080036 "toolchain/pgo-profiles",
Pirama Arumuga Nainar9d544a82020-06-29 09:25:51 -070037 "vendor/google_data/pgo_profile",
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080038 }
39)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070040
Colin Cross571cccf2019-02-04 11:22:08 -080041var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
42
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070043const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070044const profileUseInstrumentFormat = "-fprofile-use=%s"
Yi Kongb6ec66a2020-01-31 12:36:12 +080045const profileUseSamplingFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070046
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080047func getPgoProfileProjects(config android.DeviceConfig) []string {
48 return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
49 return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...)
50 })
51}
52
Yi Kong7e53c572018-02-14 18:16:12 +080053func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
Colin Cross571cccf2019-02-04 11:22:08 -080054 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -080055}
56
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070057type PgoProperties struct {
58 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070059 Instrumentation *bool
60 Sampling *bool
61 Profile_file *string `android:"arch_variant"`
62 Benchmarks []string
63 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080064 // Additional compiler flags to use when building this module
65 // for profiling (either instrumentation or sampling).
66 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070067 } `android:"arch_variant"`
68
69 PgoPresent bool `blueprint:"mutated"`
70 ShouldProfileModule bool `blueprint:"mutated"`
Yi Kong7e53c572018-02-14 18:16:12 +080071 PgoCompile bool `blueprint:"mutated"`
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -070072 PgoInstrLink bool `blueprint:"mutated"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070073}
74
75type pgo struct {
76 Properties PgoProperties
77}
78
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070079func (props *PgoProperties) isInstrumentation() bool {
80 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
81}
82
83func (props *PgoProperties) isSampling() bool {
84 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
85}
86
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070087func (pgo *pgo) props() []interface{} {
88 return []interface{}{&pgo.Properties}
89}
90
Yi Kongceb5b762020-03-20 15:22:27 +080091func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -070092 // Add to C flags iff PGO is explicitly enabled for this module.
93 if props.ShouldProfileModule {
94 flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
95 flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
96 }
97 flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag)
Yi Kongceb5b762020-03-20 15:22:27 +080098 return flags
99}
100func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
101 flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700102 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700103}
104
Yi Kong7e53c572018-02-14 18:16:12 +0800105func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800106 profileFile := *props.Pgo.Profile_file
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800107
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -0800108 // Test if the profile_file is present in any of the PGO profile projects
109 for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800110 // Bug: http://b/74395273 If the profile_file is unavailable,
111 // use a versioned file named
112 // <profile_file>.<arbitrary-version> when available. This
113 // works around an issue where ccache serves stale cache
114 // entries when the profile file has changed.
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800115 globPattern := filepath.Join(profileProject, profileFile+".*")
116 versionedProfiles, err := ctx.GlobWithDeps(globPattern, nil)
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800117 if err != nil {
118 ctx.ModuleErrorf("glob: %s", err.Error())
119 }
120
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800121 path := android.ExistentPathForSource(ctx, profileProject, profileFile)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800122 if path.Valid() {
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800123 if len(versionedProfiles) != 0 {
124 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 -0800125 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800126 return path
127 }
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800128
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800129 if len(versionedProfiles) > 1 {
130 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versionedProfiles, ", "))
131 } else if len(versionedProfiles) == 1 {
132 return android.OptionalPathForPath(android.PathForSource(ctx, versionedProfiles[0]))
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800133 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800134 }
135
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -0800136 // Record that this module's profile file is absent
137 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
138 recordMissingProfileFile(ctx, missing)
139
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800140 return android.OptionalPathForPath(nil)
141}
142
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700143func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
144 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700145 return fmt.Sprintf(profileUseInstrumentFormat, file)
146 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700147 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700148 return fmt.Sprintf(profileUseSamplingFormat, file)
149 }
150 return ""
151}
152
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700153func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
154 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700155 flags = append(flags, profileUseOtherFlags...)
156 return flags
157}
158
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700159func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800160 // Return if 'pgo' property is not present in this module.
161 if !props.PgoPresent {
162 return flags
163 }
164
Yi Kongca610d22018-04-24 10:42:02 -0700165 if props.PgoCompile {
166 profileFile := props.getPgoProfileFile(ctx)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800167 profileFilePath := profileFile.Path()
168 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700169
Colin Cross4af21ed2019-11-04 09:37:55 -0800170 flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlags...)
171 flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlags...)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700172
173 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
174 // if profileFile gets updated
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800175 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
176 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
Yi Kong92474e52020-01-16 17:04:38 -0800177
178 if props.isSampling() {
179 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
180 }
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700181 }
182 return flags
183}
184
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700185func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700186 isInstrumentation := props.isInstrumentation()
187 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700188
189 profileKindPresent := isInstrumentation || isSampling
190 filePresent := props.Pgo.Profile_file != nil
191 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
192
193 // If all three properties are absent, PGO is OFF for this module
194 if !profileKindPresent && !filePresent && !benchmarksPresent {
195 return false
196 }
197
Yi Kong84803c52020-07-21 15:38:23 +0800198 // profileKindPresent and filePresent are mandatory properties.
199 if !profileKindPresent || !filePresent {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700200 var missing []string
201 if !profileKindPresent {
202 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
203 }
204 if !filePresent {
205 missing = append(missing, "profile_file property")
206 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700207 missingProps := strings.Join(missing, ", ")
208 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
209 }
210
Yi Kong84803c52020-07-21 15:38:23 +0800211 // Benchmark property is mandatory for instrumentation PGO.
212 if isInstrumentation && !benchmarksPresent {
213 ctx.ModuleErrorf("Instrumentation PGO specification is missing benchmark property")
214 }
215
Pirama Arumuga Nainar6fc8d912017-10-05 10:25:00 -0700216 if isSampling && isInstrumentation {
217 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
218 }
219
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700220 return true
221}
222
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700223func (pgo *pgo) begin(ctx BaseModuleContext) {
224 // TODO Evaluate if we need to support PGO for host modules
225 if ctx.Host() {
226 return
227 }
228
229 // Check if PGO is needed for this module
230 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
231
232 if !pgo.Properties.PgoPresent {
233 return
234 }
235
236 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800237 // and includes 'all', 'ALL' or a benchmark listed for this module.
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700238 //
239 // TODO Validate that each benchmark instruments at least one module
240 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800241 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700242 pgoBenchmarksMap := make(map[string]bool)
243 for _, b := range strings.Split(pgoBenchmarks, ",") {
244 pgoBenchmarksMap[b] = true
245 }
246
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800247 if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
248 pgo.Properties.ShouldProfileModule = true
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700249 pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800250 } else {
251 for _, b := range pgo.Properties.Pgo.Benchmarks {
252 if pgoBenchmarksMap[b] == true {
253 pgo.Properties.ShouldProfileModule = true
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700254 pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800255 break
256 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700257 }
258 }
Yi Kong7e53c572018-02-14 18:16:12 +0800259
Pirama Arumuga Nainar807d49b2020-02-12 13:57:37 -0800260 // PGO profile use is not feasible for a Clang coverage build because
261 // -fprofile-use and -fprofile-instr-generate are incompatible.
262 if ctx.DeviceConfig().ClangCoverageEnabled() {
263 return
264 }
265
Yi Kongca610d22018-04-24 10:42:02 -0700266 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
267 proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
Yi Kong7e53c572018-02-14 18:16:12 +0800268 if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
269 pgo.Properties.PgoCompile = true
270 }
271 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700272}
273
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700274func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
275 if pgo.Properties.ShouldProfileModule {
276 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
277 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
278 }
279 return deps
280}
281
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700282func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
283 if ctx.Host() {
284 return flags
285 }
286
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700287 // Deduce PgoInstrLink property i.e. whether this module needs to be
288 // linked with profile-generation flags. Here, we're setting it if any
289 // dependency needs PGO instrumentation. It is initially set in
290 // begin() if PGO is directly enabled for this module.
291 if ctx.static() && !ctx.staticBinary() {
292 // For static libraries, check if any whole_static_libs are
293 // linked with profile generation
294 ctx.VisitDirectDeps(func(m android.Module) {
295 if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
296 if depTag.static() && depTag.wholeStatic {
297 if cc, ok := m.(*Module); ok {
298 if cc.pgo.Properties.PgoInstrLink {
299 pgo.Properties.PgoInstrLink = true
300 }
301 }
302 }
303 }
304 })
305 } else {
306 // For executables and shared libraries, check all static dependencies.
307 ctx.VisitDirectDeps(func(m android.Module) {
308 if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
309 if depTag.static() {
310 if cc, ok := m.(*Module); ok {
311 if cc.pgo.Properties.PgoInstrLink {
312 pgo.Properties.PgoInstrLink = true
313 }
314 }
315 }
316 }
317 })
318 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700319
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700320 props := pgo.Properties
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700321 // Add flags to profile this module based on its profile_kind
Pirama Arumuga Nainar1150fd72020-09-21 22:04:25 -0700322 if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink {
Yi Konga575ff32020-07-22 01:41:58 +0800323 // Instrumentation PGO use and gather flags cannot coexist.
Pirama Arumuga Nainarfe1da752020-09-02 17:44:06 +0000324 return props.addInstrumentationProfileGatherFlags(ctx, flags)
Yi Kongceb5b762020-03-20 15:22:27 +0800325 } else if props.ShouldProfileModule && props.isSampling() {
Pirama Arumuga Nainarfe1da752020-09-02 17:44:06 +0000326 flags = props.addSamplingProfileGatherFlags(ctx, flags)
Yi Kongceb5b762020-03-20 15:22:27 +0800327 } else if ctx.DeviceConfig().SamplingPGO() {
Pirama Arumuga Nainarfe1da752020-09-02 17:44:06 +0000328 flags = props.addSamplingProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700329 }
330
Colin Cross6510f912017-11-29 00:27:14 -0800331 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainarfe1da752020-09-02 17:44:06 +0000332 flags = props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700333 }
334
335 return flags
336}