blob: d5c4b87ddcc4ea99e12d84db0011e3dfd8a45d44 [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",
37 "vendor/google_data/pgo-profiles",
38 }
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"
Yi Kong61a1b982020-01-30 21:15:12 +080044const profileSamplingFlag = "-gmlt -fdebug-info-for-profiling"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070045const profileUseInstrumentFormat = "-fprofile-use=%s"
Yi Kongb6ec66a2020-01-31 12:36:12 +080046const profileUseSamplingFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070047
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080048func getPgoProfileProjects(config android.DeviceConfig) []string {
49 return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
50 return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...)
51 })
52}
53
Yi Kong7e53c572018-02-14 18:16:12 +080054func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
Colin Cross571cccf2019-02-04 11:22:08 -080055 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -080056}
57
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070058type PgoProperties struct {
59 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070060 Instrumentation *bool
61 Sampling *bool
62 Profile_file *string `android:"arch_variant"`
63 Benchmarks []string
64 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080065 // Additional compiler flags to use when building this module
66 // for profiling (either instrumentation or sampling).
67 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070068 } `android:"arch_variant"`
69
70 PgoPresent bool `blueprint:"mutated"`
71 ShouldProfileModule bool `blueprint:"mutated"`
Yi Kong7e53c572018-02-14 18:16:12 +080072 PgoCompile 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
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070091func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Colin Cross4af21ed2019-11-04 09:37:55 -080092 flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080093
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070094 if props.isInstrumentation() {
Colin Cross4af21ed2019-11-04 09:37:55 -080095 flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070096 // The profile runtime is added below in deps(). Add the below
97 // flag, which is the only other link-time action performed by
98 // the Clang driver during link.
Colin Cross4af21ed2019-11-04 09:37:55 -080099 flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700100 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700101 if props.isSampling() {
Colin Cross4af21ed2019-11-04 09:37:55 -0800102 flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
103 flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700104 }
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700105 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700106}
107
Yi Kong7e53c572018-02-14 18:16:12 +0800108func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800109 profile_file := *props.Pgo.Profile_file
110
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -0800111 // Test if the profile_file is present in any of the PGO profile projects
112 for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800113 // Bug: http://b/74395273 If the profile_file is unavailable,
114 // use a versioned file named
115 // <profile_file>.<arbitrary-version> when available. This
116 // works around an issue where ccache serves stale cache
117 // entries when the profile file has changed.
118 globPattern := filepath.Join(profileProject, profile_file+".*")
119 versioned_profiles, err := ctx.GlobWithDeps(globPattern, nil)
120 if err != nil {
121 ctx.ModuleErrorf("glob: %s", err.Error())
122 }
123
124 path := android.ExistentPathForSource(ctx, profileProject, profile_file)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800125 if path.Valid() {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800126 if len(versioned_profiles) != 0 {
127 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profile_file)+", "+strings.Join(versioned_profiles, ", "))
128 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800129 return path
130 }
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800131
132 if len(versioned_profiles) > 1 {
133 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versioned_profiles, ", "))
134 } else if len(versioned_profiles) == 1 {
135 return android.OptionalPathForPath(android.PathForSource(ctx, versioned_profiles[0]))
136 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800137 }
138
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -0800139 // Record that this module's profile file is absent
140 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
141 recordMissingProfileFile(ctx, missing)
142
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800143 return android.OptionalPathForPath(nil)
144}
145
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700146func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
147 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700148 return fmt.Sprintf(profileUseInstrumentFormat, file)
149 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700150 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700151 return fmt.Sprintf(profileUseSamplingFormat, file)
152 }
153 return ""
154}
155
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700156func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
157 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700158 flags = append(flags, profileUseOtherFlags...)
159 return flags
160}
161
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700162func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800163 // Return if 'pgo' property is not present in this module.
164 if !props.PgoPresent {
165 return flags
166 }
167
Yi Kongca610d22018-04-24 10:42:02 -0700168 if props.PgoCompile {
169 profileFile := props.getPgoProfileFile(ctx)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800170 profileFilePath := profileFile.Path()
171 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700172
Colin Cross4af21ed2019-11-04 09:37:55 -0800173 flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlags...)
174 flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlags...)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700175
176 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
177 // if profileFile gets updated
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800178 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
179 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
Yi Kong92474e52020-01-16 17:04:38 -0800180
181 if props.isSampling() {
182 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
183 }
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700184 }
185 return flags
186}
187
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700188func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700189 isInstrumentation := props.isInstrumentation()
190 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700191
192 profileKindPresent := isInstrumentation || isSampling
193 filePresent := props.Pgo.Profile_file != nil
194 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
195
196 // If all three properties are absent, PGO is OFF for this module
197 if !profileKindPresent && !filePresent && !benchmarksPresent {
198 return false
199 }
200
201 // If at least one property exists, validate that all properties exist
202 if !profileKindPresent || !filePresent || !benchmarksPresent {
203 var missing []string
204 if !profileKindPresent {
205 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
206 }
207 if !filePresent {
208 missing = append(missing, "profile_file property")
209 }
210 if !benchmarksPresent {
211 missing = append(missing, "non-empty benchmarks property")
212 }
213 missingProps := strings.Join(missing, ", ")
214 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
215 }
216
Pirama Arumuga Nainar6fc8d912017-10-05 10:25:00 -0700217 if isSampling && isInstrumentation {
218 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
219 }
220
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700221 return true
222}
223
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700224func (pgo *pgo) begin(ctx BaseModuleContext) {
225 // TODO Evaluate if we need to support PGO for host modules
226 if ctx.Host() {
227 return
228 }
229
230 // Check if PGO is needed for this module
231 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
232
233 if !pgo.Properties.PgoPresent {
234 return
235 }
236
237 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800238 // and includes 'all', 'ALL' or a benchmark listed for this module.
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700239 //
240 // TODO Validate that each benchmark instruments at least one module
241 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800242 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700243 pgoBenchmarksMap := make(map[string]bool)
244 for _, b := range strings.Split(pgoBenchmarks, ",") {
245 pgoBenchmarksMap[b] = true
246 }
247
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800248 if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
249 pgo.Properties.ShouldProfileModule = true
250 } else {
251 for _, b := range pgo.Properties.Pgo.Benchmarks {
252 if pgoBenchmarksMap[b] == true {
253 pgo.Properties.ShouldProfileModule = true
254 break
255 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700256 }
257 }
Yi Kong7e53c572018-02-14 18:16:12 +0800258
Pirama Arumuga Nainar807d49b2020-02-12 13:57:37 -0800259 // PGO profile use is not feasible for a Clang coverage build because
260 // -fprofile-use and -fprofile-instr-generate are incompatible.
261 if ctx.DeviceConfig().ClangCoverageEnabled() {
262 return
263 }
264
Yi Kongca610d22018-04-24 10:42:02 -0700265 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
266 proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
Yi Kong7e53c572018-02-14 18:16:12 +0800267 if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
268 pgo.Properties.PgoCompile = true
269 }
270 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700271}
272
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700273func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
274 if pgo.Properties.ShouldProfileModule {
275 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
276 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
277 }
278 return deps
279}
280
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700281func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
282 if ctx.Host() {
283 return flags
284 }
285
286 props := pgo.Properties
287
288 // Add flags to profile this module based on its profile_kind
289 if props.ShouldProfileModule {
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700290 return props.addProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700291 }
292
Colin Cross6510f912017-11-29 00:27:14 -0800293 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700294 return props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700295 }
296
297 return flags
298}