blob: fef962e499ef70e700b43571b8d3099285caebab [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)
30
31const pgoProfileProject = "toolchain/pgo-profiles"
32
33const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
34const profileSamplingFlag = "-gline-tables-only"
35const profileUseInstrumentFormat = "-fprofile-use=%s"
36const profileUseSamplingFormat = "-fprofile-sample-use=%s"
37
38type PgoProperties struct {
39 Pgo struct {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -070040 Instrumentation *bool
41 Sampling *bool
42 Profile_file *string `android:"arch_variant"`
43 Benchmarks []string
44 Enable_profile_use *bool `android:"arch_variant"`
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080045 // Additional compiler flags to use when building this module
46 // for profiling (either instrumentation or sampling).
47 Cflags []string `android:"arch_variant"`
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070048 } `android:"arch_variant"`
49
50 PgoPresent bool `blueprint:"mutated"`
51 ShouldProfileModule bool `blueprint:"mutated"`
52}
53
54type pgo struct {
55 Properties PgoProperties
56}
57
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070058func (props *PgoProperties) isInstrumentation() bool {
59 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
60}
61
62func (props *PgoProperties) isSampling() bool {
63 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
64}
65
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070066func (pgo *pgo) props() []interface{} {
67 return []interface{}{&pgo.Properties}
68}
69
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070070func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar690ed552017-12-13 16:48:20 -080071 flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
72
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070073 if props.isInstrumentation() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070074 flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
75 // The profile runtime is added below in deps(). Add the below
76 // flag, which is the only other link-time action performed by
77 // the Clang driver during link.
78 flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070079 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070080 if props.isSampling() {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070081 flags.CFlags = append(flags.CFlags, profileSamplingFlag)
82 flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070083 }
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -070084 return flags
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070085}
86
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070087func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
88 if props.isInstrumentation() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070089 return fmt.Sprintf(profileUseInstrumentFormat, file)
90 }
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070091 if props.isSampling() {
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070092 return fmt.Sprintf(profileUseSamplingFormat, file)
93 }
94 return ""
95}
96
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -070097func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
98 flags := []string{props.profileUseFlag(ctx, file)}
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -070099 flags = append(flags, profileUseOtherFlags...)
100 return flags
101}
102
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700103func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
Pirama Arumuga Nainar6aeed8b2017-10-16 13:31:40 -0700104 // Skip -fprofile-use if 'enable_profile_use' property is set
105 if props.Pgo.Enable_profile_use != nil && *props.Pgo.Enable_profile_use == false {
106 return flags
107 }
108
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700109 // If the PGO profiles project is found, and this module has PGO
110 // enabled, add flags to use the profile
111 if profilesDir := getPgoProfilesDir(ctx); props.PgoPresent && profilesDir.Valid() {
112 profileFile := android.PathForSource(ctx, profilesDir.String(), *props.Pgo.Profile_file)
113 profileUseFlags := props.profileUseFlags(ctx, profileFile.String())
114
115 flags.CFlags = append(flags.CFlags, profileUseFlags...)
116 flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
117
118 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
119 // if profileFile gets updated
120 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFile)
121 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFile)
122 }
123 return flags
124}
125
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700126func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700127 isInstrumentation := props.isInstrumentation()
128 isSampling := props.isSampling()
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700129
130 profileKindPresent := isInstrumentation || isSampling
131 filePresent := props.Pgo.Profile_file != nil
132 benchmarksPresent := len(props.Pgo.Benchmarks) > 0
133
134 // If all three properties are absent, PGO is OFF for this module
135 if !profileKindPresent && !filePresent && !benchmarksPresent {
136 return false
137 }
138
139 // If at least one property exists, validate that all properties exist
140 if !profileKindPresent || !filePresent || !benchmarksPresent {
141 var missing []string
142 if !profileKindPresent {
143 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
144 }
145 if !filePresent {
146 missing = append(missing, "profile_file property")
147 }
148 if !benchmarksPresent {
149 missing = append(missing, "non-empty benchmarks property")
150 }
151 missingProps := strings.Join(missing, ", ")
152 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
153 }
154
155 // Sampling not supported yet
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700156 if isSampling {
157 ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
158 }
159
Pirama Arumuga Nainar6fc8d912017-10-05 10:25:00 -0700160 if isSampling && isInstrumentation {
161 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
162 }
163
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700164 return true
165}
166
167func getPgoProfilesDir(ctx ModuleContext) android.OptionalPath {
168 return android.ExistentPathForSource(ctx, "", pgoProfileProject)
169}
170
171func (pgo *pgo) begin(ctx BaseModuleContext) {
172 // TODO Evaluate if we need to support PGO for host modules
173 if ctx.Host() {
174 return
175 }
176
177 // Check if PGO is needed for this module
178 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
179
180 if !pgo.Properties.PgoPresent {
181 return
182 }
183
184 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
185 // and includes a benchmark listed for this module
186 //
187 // TODO Validate that each benchmark instruments at least one module
188 pgo.Properties.ShouldProfileModule = false
Colin Cross6510f912017-11-29 00:27:14 -0800189 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700190 pgoBenchmarksMap := make(map[string]bool)
191 for _, b := range strings.Split(pgoBenchmarks, ",") {
192 pgoBenchmarksMap[b] = true
193 }
194
195 for _, b := range pgo.Properties.Pgo.Benchmarks {
196 if pgoBenchmarksMap[b] == true {
197 pgo.Properties.ShouldProfileModule = true
198 break
199 }
200 }
201}
202
Pirama Arumuga Nainar49b53d52017-10-04 16:47:29 -0700203func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {
204 if pgo.Properties.ShouldProfileModule {
205 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain())
206 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary)
207 }
208 return deps
209}
210
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700211func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
212 if ctx.Host() {
213 return flags
214 }
215
216 props := pgo.Properties
217
218 // Add flags to profile this module based on its profile_kind
219 if props.ShouldProfileModule {
Pirama Arumuga Nainar3f5bb9c2017-10-10 10:47:41 -0700220 return props.addProfileGatherFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700221 }
222
Colin Cross6510f912017-11-29 00:27:14 -0800223 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
Pirama Arumuga Nainar0fdfc452017-10-10 11:00:18 -0700224 return props.addProfileUseFlags(ctx, flags)
Pirama Arumuga Nainarada83ec2017-08-31 23:38:27 -0700225 }
226
227 return flags
228}