blob: 7ac5b2a06a1e0da1118aac21ff5d7912d39159a8 [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
41type PgoProperties struct {
42 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070043 Instrumentation *bool
44 Sampling *bool
45 Profile_file *string `android:"arch_variant"`
46 Benchmarks []string
47 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080048 // Additional compiler flags to use when building this module
49 // for profiling (either instrumentation or sampling).
50 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070051 } `android:"arch_variant"`
52
53 PgoPresent bool `blueprint:"mutated"`
54 ShouldProfileModule bool `blueprint:"mutated"`
55}
56
57type pgo struct {
58 Properties PgoProperties
59}
60
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070061func (props *PgoProperties) isInstrumentation() bool {
62 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
63}
64
65func (props *PgoProperties) isSampling() bool {
66 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
67}
68
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070069func (pgo *pgo) props() []interface{} {
70 return []interface{}{&pgo.Properties}
71}
72
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070073func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080074 flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
75
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070076 if props.isInstrumentation() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070077 flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
78 // The profile runtime is added below in deps(). Add the below
79 // flag, which is the only other link-time action performed by
80 // the Clang driver during link.
81 flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070082 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070083 if props.isSampling() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070084 flags.CFlags = append(flags.CFlags, profileSamplingFlag)
85 flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070086 }
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070087 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070088}
89
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -080090func (props *PgoProperties) getPgoProfileFile(ctx ModuleContext) android.OptionalPath {
91 // Test if the profile_file is present in any of the pgoProfileProjects
92 for _, profileProject := range pgoProfileProjects {
93 path := android.ExistentPathForSource(ctx, "", profileProject, *props.Pgo.Profile_file)
94 if path.Valid() {
95 return path
96 }
97 }
98
99 return android.OptionalPathForPath(nil)
100}
101
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700102func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
103 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700104 return fmt.Sprintf(profileUseInstrumentFormat, file)
105 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700106 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700107 return fmt.Sprintf(profileUseSamplingFormat, file)
108 }
109 return ""
110}
111
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700112func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
113 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700114 flags = append(flags, profileUseOtherFlags...)
115 return flags
116}
117
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700118func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800119 // Return if 'pgo' property is not present in this module.
120 if !props.PgoPresent {
121 return flags
122 }
123
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -0700124 // Skip -fprofile-use if 'enable_profile_use' property is set
125 if props.Pgo.Enable_profile_use != nil && *props.Pgo.Enable_profile_use == false {
126 return flags
127 }
128
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800129 // If the profile file is found, add flags to use the profile
130 if profileFile := props.getPgoProfileFile(ctx); profileFile.Valid() {
131 profileFilePath := profileFile.Path()
132 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700133
134 flags.CFlags = append(flags.CFlags, profileUseFlags...)
135 flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
136
137 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
138 // if profileFile gets updated
Pirama Arumuga Nainar64946fe2018-01-17 14:00:53 -0800139 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
140 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700141 }
142 return flags
143}
144
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700145func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700146 isInstrumentation := props.isInstrumentation()
147 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700148
149 profileKindPresent := isInstrumentation || isSampling
150 filePresent := props.Pgo.Profile_file != nil
151 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
152
153 // If all three properties are absent, PGO is OFF for this module
154 if !profileKindPresent && !filePresent && !benchmarksPresent {
155 return false
156 }
157
158 // If at least one property exists, validate that all properties exist
159 if !profileKindPresent || !filePresent || !benchmarksPresent {
160 var missing []string
161 if !profileKindPresent {
162 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
163 }
164 if !filePresent {
165 missing = append(missing, "profile_file property")
166 }
167 if !benchmarksPresent {
168 missing = append(missing, "non-empty benchmarks property")
169 }
170 missingProps := strings.Join(missing, ", ")
171 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
172 }
173
174 // Sampling not supported yet
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700175 if isSampling {
176 ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
177 }
178
Pirama Arumuga Nainar6fc8d912017-10-05 10:25:00 -0700179 if isSampling && isInstrumentation {
180 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
181 }
182
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700183 return true
184}
185
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700186func (pgo *pgo) begin(ctx BaseModuleContext) {
187 // TODO Evaluate if we need to support PGO for host modules
188 if ctx.Host() {
189 return
190 }
191
192 // Check if PGO is needed for this module
193 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
194
195 if !pgo.Properties.PgoPresent {
196 return
197 }
198
199 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
200 // and includes a benchmark listed for this module
201 //
202 // TODO Validate that each benchmark instruments at least one module
203 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800204 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700205 pgoBenchmarksMap := make(map[string]bool)
206 for _, b := range strings.Split(pgoBenchmarks, ",") {
207 pgoBenchmarksMap[b] = true
208 }
209
210 for _, b := range pgo.Properties.Pgo.Benchmarks {
211 if pgoBenchmarksMap[b] == true {
212 pgo.Properties.ShouldProfileModule = true
213 break
214 }
215 }
216}
217
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700218func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
219 if pgo.Properties.ShouldProfileModule {
220 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
221 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
222 }
223 return deps
224}
225
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700226func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
227 if ctx.Host() {
228 return flags
229 }
230
231 props := pgo.Properties
232
233 // Add flags to profile this module based on its profile_kind
234 if props.ShouldProfileModule {
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700235 return props.addProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700236 }
237
Colin Cross6510f912017-11-29 00:27:14 -0800238 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700239 return props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700240 }
241
242 return flags
243}