blob: d39e4290d315204d9ef7b0da8c21f34ec4e99ef9 [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
22 "android/soong/android"
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070023 "android/soong/cc/config"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070024)
25
26var (
27 // Add flags to ignore warnings that profiles are old or missing for
28 // some functions
Pirama Arumuga Nainarf4c0baf2017-09-28 14:35:15 -070029 profileUseOtherFlags = []string{"-Wno-backend-plugin"}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070030
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080031 globalPgoProfileProjects = []string{
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080032 "toolchain/pgo-profiles",
33 "vendor/google_data/pgo-profiles",
34 }
35)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070036
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080037const pgoProfileProjectsConfigKey = "PgoProfileProjects"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070038const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
39const profileSamplingFlag = "-gline-tables-only"
40const profileUseInstrumentFormat = "-fprofile-use=%s"
41const profileUseSamplingFormat = "-fprofile-sample-use=%s"
42
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080043func getPgoProfileProjects(config android.DeviceConfig) []string {
44 return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
45 return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...)
46 })
47}
48
Yi Kong7e53c572018-02-14 18:16:12 +080049func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -080050 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFile).Store(missing, true)
51}
52
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070053type PgoProperties struct {
54 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070055 Instrumentation *bool
56 Sampling *bool
57 Profile_file *string `android:"arch_variant"`
58 Benchmarks []string
59 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080060 // Additional compiler flags to use when building this module
61 // for profiling (either instrumentation or sampling).
62 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070063 } `android:"arch_variant"`
64
65 PgoPresent bool `blueprint:"mutated"`
66 ShouldProfileModule bool `blueprint:"mutated"`
Yi Kong7e53c572018-02-14 18:16:12 +080067 PgoCompile bool `blueprint:"mutated"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070068}
69
70type pgo struct {
71 Properties PgoProperties
72}
73
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070074func (props *PgoProperties) isInstrumentation() bool {
75 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
76}
77
78func (props *PgoProperties) isSampling() bool {
79 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
80}
81
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070082func (pgo *pgo) props() []interface{} {
83 return []interface{}{&pgo.Properties}
84}
85
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070086func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080087 flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
88
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070089 if props.isInstrumentation() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070090 flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
91 // The profile runtime is added below in deps(). Add the below
92 // flag, which is the only other link-time action performed by
93 // the Clang driver during link.
94 flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070095 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070096 if props.isSampling() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070097 flags.CFlags = append(flags.CFlags, profileSamplingFlag)
98 flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070099 }
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700100 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700101}
102
Yi Kong7e53c572018-02-14 18:16:12 +0800103func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800104 profile_file := *props.Pgo.Profile_file
105
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -0800106 // Test if the profile_file is present in any of the PGO profile projects
107 for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800108 // Bug: http://b/74395273 If the profile_file is unavailable,
109 // use a versioned file named
110 // <profile_file>.<arbitrary-version> when available. This
111 // works around an issue where ccache serves stale cache
112 // entries when the profile file has changed.
113 globPattern := filepath.Join(profileProject, profile_file+".*")
114 versioned_profiles, err := ctx.GlobWithDeps(globPattern, nil)
115 if err != nil {
116 ctx.ModuleErrorf("glob: %s", err.Error())
117 }
118
119 path := android.ExistentPathForSource(ctx, profileProject, profile_file)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800120 if path.Valid() {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800121 if len(versioned_profiles) != 0 {
122 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profile_file)+", "+strings.Join(versioned_profiles, ", "))
123 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800124 return path
125 }
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800126
127 if len(versioned_profiles) > 1 {
128 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versioned_profiles, ", "))
129 } else if len(versioned_profiles) == 1 {
130 return android.OptionalPathForPath(android.PathForSource(ctx, versioned_profiles[0]))
131 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800132 }
133
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -0800134 // Record that this module's profile file is absent
135 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
136 recordMissingProfileFile(ctx, missing)
137
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800138 return android.OptionalPathForPath(nil)
139}
140
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700141func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
142 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700143 return fmt.Sprintf(profileUseInstrumentFormat, file)
144 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700145 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700146 return fmt.Sprintf(profileUseSamplingFormat, file)
147 }
148 return ""
149}
150
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700151func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
152 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700153 flags = append(flags, profileUseOtherFlags...)
154 return flags
155}
156
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700157func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800158 // Return if 'pgo' property is not present in this module.
159 if !props.PgoPresent {
160 return flags
161 }
162
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -0700163 // Skip -fprofile-use if 'enable_profile_use' property is set
164 if props.Pgo.Enable_profile_use != nil && *props.Pgo.Enable_profile_use == false {
165 return flags
166 }
167
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800168 // If the profile file is found, add flags to use the profile
169 if profileFile := props.getPgoProfileFile(ctx); profileFile.Valid() {
170 profileFilePath := profileFile.Path()
171 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700172
173 flags.CFlags = append(flags.CFlags, profileUseFlags...)
174 flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
175
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)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700180 }
181 return flags
182}
183
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700184func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700185 isInstrumentation := props.isInstrumentation()
186 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700187
188 profileKindPresent := isInstrumentation || isSampling
189 filePresent := props.Pgo.Profile_file != nil
190 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
191
192 // If all three properties are absent, PGO is OFF for this module
193 if !profileKindPresent && !filePresent && !benchmarksPresent {
194 return false
195 }
196
197 // If at least one property exists, validate that all properties exist
198 if !profileKindPresent || !filePresent || !benchmarksPresent {
199 var missing []string
200 if !profileKindPresent {
201 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
202 }
203 if !filePresent {
204 missing = append(missing, "profile_file property")
205 }
206 if !benchmarksPresent {
207 missing = append(missing, "non-empty benchmarks property")
208 }
209 missingProps := strings.Join(missing, ", ")
210 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
211 }
212
213 // Sampling not supported yet
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700214 if isSampling {
215 ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
216 }
217
Pirama Arumuga Nainar6fc8d912017-10-05 10:25:00 -0700218 if isSampling && isInstrumentation {
219 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
220 }
221
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700222 return true
223}
224
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700225func (pgo *pgo) begin(ctx BaseModuleContext) {
226 // TODO Evaluate if we need to support PGO for host modules
227 if ctx.Host() {
228 return
229 }
230
231 // Check if PGO is needed for this module
232 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
233
234 if !pgo.Properties.PgoPresent {
235 return
236 }
237
238 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800239 // and includes 'all', 'ALL' or a benchmark listed for this module.
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700240 //
241 // TODO Validate that each benchmark instruments at least one module
242 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800243 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700244 pgoBenchmarksMap := make(map[string]bool)
245 for _, b := range strings.Split(pgoBenchmarks, ",") {
246 pgoBenchmarksMap[b] = true
247 }
248
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800249 if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
250 pgo.Properties.ShouldProfileModule = true
251 } else {
252 for _, b := range pgo.Properties.Pgo.Benchmarks {
253 if pgoBenchmarksMap[b] == true {
254 pgo.Properties.ShouldProfileModule = true
255 break
256 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700257 }
258 }
Yi Kong7e53c572018-02-14 18:16:12 +0800259
260 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
261 if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
262 pgo.Properties.PgoCompile = true
263 }
264 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700265}
266
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700267func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
268 if pgo.Properties.ShouldProfileModule {
269 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
270 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
271 }
272 return deps
273}
274
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700275func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
276 if ctx.Host() {
277 return flags
278 }
279
280 props := pgo.Properties
281
282 // Add flags to profile this module based on its profile_kind
283 if props.ShouldProfileModule {
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700284 return props.addProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700285 }
286
Colin Cross6510f912017-11-29 00:27:14 -0800287 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700288 return props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700289 }
290
291 return flags
292}