blob: 9363916a73421dc920063d4c893f9d9bea9f514e [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
30 // some functions
Pirama Arumuga Nainarf4c0baf2017-09-28 14:35:15 -070031 profileUseOtherFlags = []string{"-Wno-backend-plugin"}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070032
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080033 globalPgoProfileProjects = []string{
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080034 "toolchain/pgo-profiles",
35 "vendor/google_data/pgo-profiles",
36 }
37)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070038
Colin Cross571cccf2019-02-04 11:22:08 -080039var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
40
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070041const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
42const profileSamplingFlag = "-gline-tables-only"
43const profileUseInstrumentFormat = "-fprofile-use=%s"
44const profileUseSamplingFormat = "-fprofile-sample-use=%s"
45
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080046func getPgoProfileProjects(config android.DeviceConfig) []string {
47 return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
48 return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...)
49 })
50}
51
Yi Kong7e53c572018-02-14 18:16:12 +080052func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
Colin Cross571cccf2019-02-04 11:22:08 -080053 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -080054}
55
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070056type PgoProperties struct {
57 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070058 Instrumentation *bool
59 Sampling *bool
60 Profile_file *string `android:"arch_variant"`
61 Benchmarks []string
62 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080063 // Additional compiler flags to use when building this module
64 // for profiling (either instrumentation or sampling).
65 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070066 } `android:"arch_variant"`
67
68 PgoPresent bool `blueprint:"mutated"`
69 ShouldProfileModule bool `blueprint:"mutated"`
Yi Kong7e53c572018-02-14 18:16:12 +080070 PgoCompile bool `blueprint:"mutated"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070071}
72
73type pgo struct {
74 Properties PgoProperties
75}
76
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070077func (props *PgoProperties) isInstrumentation() bool {
78 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
79}
80
81func (props *PgoProperties) isSampling() bool {
82 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
83}
84
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070085func (pgo *pgo) props() []interface{} {
86 return []interface{}{&pgo.Properties}
87}
88
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070089func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080090 flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
91
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070092 if props.isInstrumentation() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070093 flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
94 // The profile runtime is added below in deps(). Add the below
95 // flag, which is the only other link-time action performed by
96 // the Clang driver during link.
97 flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070098 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070099 if props.isSampling() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700100 flags.CFlags = append(flags.CFlags, profileSamplingFlag)
101 flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700102 }
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700103 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700104}
105
Yi Kong7e53c572018-02-14 18:16:12 +0800106func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800107 profile_file := *props.Pgo.Profile_file
108
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -0800109 // Test if the profile_file is present in any of the PGO profile projects
110 for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800111 // Bug: http://b/74395273 If the profile_file is unavailable,
112 // use a versioned file named
113 // <profile_file>.<arbitrary-version> when available. This
114 // works around an issue where ccache serves stale cache
115 // entries when the profile file has changed.
116 globPattern := filepath.Join(profileProject, profile_file+".*")
117 versioned_profiles, err := ctx.GlobWithDeps(globPattern, nil)
118 if err != nil {
119 ctx.ModuleErrorf("glob: %s", err.Error())
120 }
121
122 path := android.ExistentPathForSource(ctx, profileProject, profile_file)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800123 if path.Valid() {
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800124 if len(versioned_profiles) != 0 {
125 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profile_file)+", "+strings.Join(versioned_profiles, ", "))
126 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800127 return path
128 }
Pirama Arumuga Nainar8aed42c2018-03-08 22:56:37 -0800129
130 if len(versioned_profiles) > 1 {
131 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versioned_profiles, ", "))
132 } else if len(versioned_profiles) == 1 {
133 return android.OptionalPathForPath(android.PathForSource(ctx, versioned_profiles[0]))
134 }
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800135 }
136
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -0800137 // Record that this module's profile file is absent
138 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
139 recordMissingProfileFile(ctx, missing)
140
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800141 return android.OptionalPathForPath(nil)
142}
143
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700144func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
145 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700146 return fmt.Sprintf(profileUseInstrumentFormat, file)
147 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700148 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700149 return fmt.Sprintf(profileUseSamplingFormat, file)
150 }
151 return ""
152}
153
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700154func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
155 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700156 flags = append(flags, profileUseOtherFlags...)
157 return flags
158}
159
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700160func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800161 // Return if 'pgo' property is not present in this module.
162 if !props.PgoPresent {
163 return flags
164 }
165
Yi Kongca610d22018-04-24 10:42:02 -0700166 if props.PgoCompile {
167 profileFile := props.getPgoProfileFile(ctx)
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800168 profileFilePath := profileFile.Path()
169 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700170
171 flags.CFlags = append(flags.CFlags, profileUseFlags...)
172 flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
173
174 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
175 // if profileFile gets updated
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800176 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
177 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700178 }
179 return flags
180}
181
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700182func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700183 isInstrumentation := props.isInstrumentation()
184 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700185
186 profileKindPresent := isInstrumentation || isSampling
187 filePresent := props.Pgo.Profile_file != nil
188 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
189
190 // If all three properties are absent, PGO is OFF for this module
191 if !profileKindPresent && !filePresent && !benchmarksPresent {
192 return false
193 }
194
195 // If at least one property exists, validate that all properties exist
196 if !profileKindPresent || !filePresent || !benchmarksPresent {
197 var missing []string
198 if !profileKindPresent {
199 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
200 }
201 if !filePresent {
202 missing = append(missing, "profile_file property")
203 }
204 if !benchmarksPresent {
205 missing = append(missing, "non-empty benchmarks property")
206 }
207 missingProps := strings.Join(missing, ", ")
208 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
209 }
210
211 // Sampling not supported yet
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700212 if isSampling {
213 ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
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
249 } else {
250 for _, b := range pgo.Properties.Pgo.Benchmarks {
251 if pgoBenchmarksMap[b] == true {
252 pgo.Properties.ShouldProfileModule = true
253 break
254 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700255 }
256 }
Yi Kong7e53c572018-02-14 18:16:12 +0800257
Yi Kongca610d22018-04-24 10:42:02 -0700258 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
259 proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
Yi Kong7e53c572018-02-14 18:16:12 +0800260 if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
261 pgo.Properties.PgoCompile = true
262 }
263 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700264}
265
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700266func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
267 if pgo.Properties.ShouldProfileModule {
268 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
269 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
270 }
271 return deps
272}
273
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700274func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
275 if ctx.Host() {
276 return flags
277 }
278
279 props := pgo.Properties
280
281 // Add flags to profile this module based on its profile_kind
282 if props.ShouldProfileModule {
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700283 return props.addProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700284 }
285
Colin Cross6510f912017-11-29 00:27:14 -0800286 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700287 return props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700288 }
289
290 return flags
291}