blob: 779ef39dec8078a4dd325a21901466cf0a56f927 [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"
19 "strings"
20
21 "android/soong/android"
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070022 "android/soong/cc/config"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070023)
24
25var (
26 // Add flags to ignore warnings that profiles are old or missing for
27 // some functions
Pirama Arumuga Nainarf4c0baf2017-09-28 14:35:15 -070028 profileUseOtherFlags = []string{"-Wno-backend-plugin"}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070029
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080030 globalPgoProfileProjects = []string{
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080031 "toolchain/pgo-profiles",
32 "vendor/google_data/pgo-profiles",
33 }
34)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070035
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080036const pgoProfileProjectsConfigKey = "PgoProfileProjects"
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070037const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
38const profileSamplingFlag = "-gline-tables-only"
39const profileUseInstrumentFormat = "-fprofile-use=%s"
40const profileUseSamplingFormat = "-fprofile-sample-use=%s"
41
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -080042func getPgoProfileProjects(config android.DeviceConfig) []string {
43 return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
44 return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...)
45 })
46}
47
Yi Kong7e53c572018-02-14 18:16:12 +080048func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -080049 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFile).Store(missing, true)
50}
51
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070052type PgoProperties struct {
53 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070054 Instrumentation *bool
55 Sampling *bool
56 Profile_file *string `android:"arch_variant"`
57 Benchmarks []string
58 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080059 // Additional compiler flags to use when building this module
60 // for profiling (either instrumentation or sampling).
61 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070062 } `android:"arch_variant"`
63
64 PgoPresent bool `blueprint:"mutated"`
65 ShouldProfileModule bool `blueprint:"mutated"`
Yi Kong7e53c572018-02-14 18:16:12 +080066 PgoCompile bool `blueprint:"mutated"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070067}
68
69type pgo struct {
70 Properties PgoProperties
71}
72
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070073func (props *PgoProperties) isInstrumentation() bool {
74 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
75}
76
77func (props *PgoProperties) isSampling() bool {
78 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
79}
80
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070081func (pgo *pgo) props() []interface{} {
82 return []interface{}{&pgo.Properties}
83}
84
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070085func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080086 flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
87
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070088 if props.isInstrumentation() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070089 flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
90 // The profile runtime is added below in deps(). Add the below
91 // flag, which is the only other link-time action performed by
92 // the Clang driver during link.
93 flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070094 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070095 if props.isSampling() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070096 flags.CFlags = append(flags.CFlags, profileSamplingFlag)
97 flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070098 }
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070099 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700100}
101
Yi Kong7e53c572018-02-14 18:16:12 +0800102func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
Pirama Arumuga Nainar49540802018-01-29 23:11:42 -0800103 // Test if the profile_file is present in any of the PGO profile projects
104 for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800105 path := android.ExistentPathForSource(ctx, "", profileProject, *props.Pgo.Profile_file)
106 if path.Valid() {
107 return path
108 }
109 }
110
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -0800111 // Record that this module's profile file is absent
112 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
113 recordMissingProfileFile(ctx, missing)
114
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800115 return android.OptionalPathForPath(nil)
116}
117
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700118func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
119 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700120 return fmt.Sprintf(profileUseInstrumentFormat, file)
121 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700122 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700123 return fmt.Sprintf(profileUseSamplingFormat, file)
124 }
125 return ""
126}
127
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700128func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
129 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700130 flags = append(flags, profileUseOtherFlags...)
131 return flags
132}
133
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700134func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800135 // Return if 'pgo' property is not present in this module.
136 if !props.PgoPresent {
137 return flags
138 }
139
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -0700140 // Skip -fprofile-use if 'enable_profile_use' property is set
141 if props.Pgo.Enable_profile_use != nil && *props.Pgo.Enable_profile_use == false {
142 return flags
143 }
144
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800145 // If the profile file is found, add flags to use the profile
146 if profileFile := props.getPgoProfileFile(ctx); profileFile.Valid() {
147 profileFilePath := profileFile.Path()
148 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700149
150 flags.CFlags = append(flags.CFlags, profileUseFlags...)
151 flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
152
153 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
154 // if profileFile gets updated
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800155 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
156 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700157 }
158 return flags
159}
160
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700161func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700162 isInstrumentation := props.isInstrumentation()
163 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700164
165 profileKindPresent := isInstrumentation || isSampling
166 filePresent := props.Pgo.Profile_file != nil
167 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
168
169 // If all three properties are absent, PGO is OFF for this module
170 if !profileKindPresent && !filePresent && !benchmarksPresent {
171 return false
172 }
173
174 // If at least one property exists, validate that all properties exist
175 if !profileKindPresent || !filePresent || !benchmarksPresent {
176 var missing []string
177 if !profileKindPresent {
178 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
179 }
180 if !filePresent {
181 missing = append(missing, "profile_file property")
182 }
183 if !benchmarksPresent {
184 missing = append(missing, "non-empty benchmarks property")
185 }
186 missingProps := strings.Join(missing, ", ")
187 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
188 }
189
190 // Sampling not supported yet
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700191 if isSampling {
192 ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
193 }
194
Pirama Arumuga Nainar6fc8d912017-10-05 10:25:00 -0700195 if isSampling && isInstrumentation {
196 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
197 }
198
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700199 return true
200}
201
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700202func (pgo *pgo) begin(ctx BaseModuleContext) {
203 // TODO Evaluate if we need to support PGO for host modules
204 if ctx.Host() {
205 return
206 }
207
208 // Check if PGO is needed for this module
209 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
210
211 if !pgo.Properties.PgoPresent {
212 return
213 }
214
215 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800216 // and includes 'all', 'ALL' or a benchmark listed for this module.
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700217 //
218 // TODO Validate that each benchmark instruments at least one module
219 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800220 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700221 pgoBenchmarksMap := make(map[string]bool)
222 for _, b := range strings.Split(pgoBenchmarks, ",") {
223 pgoBenchmarksMap[b] = true
224 }
225
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800226 if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
227 pgo.Properties.ShouldProfileModule = true
228 } else {
229 for _, b := range pgo.Properties.Pgo.Benchmarks {
230 if pgoBenchmarksMap[b] == true {
231 pgo.Properties.ShouldProfileModule = true
232 break
233 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700234 }
235 }
Yi Kong7e53c572018-02-14 18:16:12 +0800236
237 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
238 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
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700244func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
245 if pgo.Properties.ShouldProfileModule {
246 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
247 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
248 }
249 return deps
250}
251
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700252func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
253 if ctx.Host() {
254 return flags
255 }
256
257 props := pgo.Properties
258
259 // Add flags to profile this module based on its profile_kind
260 if props.ShouldProfileModule {
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700261 return props.addProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700262 }
263
Colin Cross6510f912017-11-29 00:27:14 -0800264 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700265 return props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700266 }
267
268 return flags
269}