blob: 3ce67be7ab9507299181e7564c16589aecf19e89 [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 Nainar64946fe2018-01-17 14:00:53 -080030 pgoProfileProjects = []string{
31 "toolchain/pgo-profiles",
32 "vendor/google_data/pgo-profiles",
33 }
34)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070035
36const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
37const profileSamplingFlag = "-gline-tables-only"
38const profileUseInstrumentFormat = "-fprofile-use=%s"
39const profileUseSamplingFormat = "-fprofile-sample-use=%s"
40
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -080041func recordMissingProfileFile(ctx ModuleContext, missing string) {
42 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFile).Store(missing, true)
43}
44
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070045type PgoProperties struct {
46 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070047 Instrumentation *bool
48 Sampling *bool
49 Profile_file *string `android:"arch_variant"`
50 Benchmarks []string
51 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080052 // Additional compiler flags to use when building this module
53 // for profiling (either instrumentation or sampling).
54 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070055 } `android:"arch_variant"`
56
57 PgoPresent bool `blueprint:"mutated"`
58 ShouldProfileModule bool `blueprint:"mutated"`
59}
60
61type pgo struct {
62 Properties PgoProperties
63}
64
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070065func (props *PgoProperties) isInstrumentation() bool {
66 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
67}
68
69func (props *PgoProperties) isSampling() bool {
70 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
71}
72
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070073func (pgo *pgo) props() []interface{} {
74 return []interface{}{&pgo.Properties}
75}
76
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070077func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080078 flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
79
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070080 if props.isInstrumentation() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070081 flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
82 // The profile runtime is added below in deps(). Add the below
83 // flag, which is the only other link-time action performed by
84 // the Clang driver during link.
85 flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070086 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070087 if props.isSampling() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070088 flags.CFlags = append(flags.CFlags, profileSamplingFlag)
89 flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070090 }
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070091 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070092}
93
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080094func (props *PgoProperties) getPgoProfileFile(ctx ModuleContext) android.OptionalPath {
95 // Test if the profile_file is present in any of the pgoProfileProjects
96 for _, profileProject := range pgoProfileProjects {
97 path := android.ExistentPathForSource(ctx, "", profileProject, *props.Pgo.Profile_file)
98 if path.Valid() {
99 return path
100 }
101 }
102
Pirama Arumuga Nainar28316d42018-01-29 09:18:45 -0800103 // Record that this module's profile file is absent
104 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
105 recordMissingProfileFile(ctx, missing)
106
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800107 return android.OptionalPathForPath(nil)
108}
109
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700110func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
111 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700112 return fmt.Sprintf(profileUseInstrumentFormat, file)
113 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700114 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700115 return fmt.Sprintf(profileUseSamplingFormat, file)
116 }
117 return ""
118}
119
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700120func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
121 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700122 flags = append(flags, profileUseOtherFlags...)
123 return flags
124}
125
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700126func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800127 // Return if 'pgo' property is not present in this module.
128 if !props.PgoPresent {
129 return flags
130 }
131
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -0700132 // Skip -fprofile-use if 'enable_profile_use' property is set
133 if props.Pgo.Enable_profile_use != nil && *props.Pgo.Enable_profile_use == false {
134 return flags
135 }
136
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800137 // If the profile file is found, add flags to use the profile
138 if profileFile := props.getPgoProfileFile(ctx); profileFile.Valid() {
139 profileFilePath := profileFile.Path()
140 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700141
142 flags.CFlags = append(flags.CFlags, profileUseFlags...)
143 flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
144
145 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
146 // if profileFile gets updated
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800147 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
148 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700149 }
150 return flags
151}
152
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700153func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700154 isInstrumentation := props.isInstrumentation()
155 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700156
157 profileKindPresent := isInstrumentation || isSampling
158 filePresent := props.Pgo.Profile_file != nil
159 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
160
161 // If all three properties are absent, PGO is OFF for this module
162 if !profileKindPresent && !filePresent && !benchmarksPresent {
163 return false
164 }
165
166 // If at least one property exists, validate that all properties exist
167 if !profileKindPresent || !filePresent || !benchmarksPresent {
168 var missing []string
169 if !profileKindPresent {
170 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
171 }
172 if !filePresent {
173 missing = append(missing, "profile_file property")
174 }
175 if !benchmarksPresent {
176 missing = append(missing, "non-empty benchmarks property")
177 }
178 missingProps := strings.Join(missing, ", ")
179 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
180 }
181
182 // Sampling not supported yet
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700183 if isSampling {
184 ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
185 }
186
Pirama Arumuga Nainar6fc8d912017-10-05 10:25:00 -0700187 if isSampling && isInstrumentation {
188 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
189 }
190
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700191 return true
192}
193
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700194func (pgo *pgo) begin(ctx BaseModuleContext) {
195 // TODO Evaluate if we need to support PGO for host modules
196 if ctx.Host() {
197 return
198 }
199
200 // Check if PGO is needed for this module
201 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
202
203 if !pgo.Properties.PgoPresent {
204 return
205 }
206
207 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800208 // and includes 'all', 'ALL' or a benchmark listed for this module.
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700209 //
210 // TODO Validate that each benchmark instruments at least one module
211 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800212 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700213 pgoBenchmarksMap := make(map[string]bool)
214 for _, b := range strings.Split(pgoBenchmarks, ",") {
215 pgoBenchmarksMap[b] = true
216 }
217
Pirama Arumuga Nainare236b5a2018-01-22 19:10:19 -0800218 if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
219 pgo.Properties.ShouldProfileModule = true
220 } else {
221 for _, b := range pgo.Properties.Pgo.Benchmarks {
222 if pgoBenchmarksMap[b] == true {
223 pgo.Properties.ShouldProfileModule = true
224 break
225 }
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700226 }
227 }
228}
229
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700230func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
231 if pgo.Properties.ShouldProfileModule {
232 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
233 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
234 }
235 return deps
236}
237
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700238func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
239 if ctx.Host() {
240 return flags
241 }
242
243 props := pgo.Properties
244
245 // Add flags to profile this module based on its profile_kind
246 if props.ShouldProfileModule {
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700247 return props.addProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700248 }
249
Colin Cross6510f912017-11-29 00:27:14 -0800250 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700251 return props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700252 }
253
254 return flags
255}