github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cc/pgo.go (about) 1 // 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 15 package cc 16 17 import ( 18 "fmt" 19 "path/filepath" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/cc/config" 24 ) 25 26 var ( 27 // Add flags to ignore warnings that profiles are old or missing for 28 // some functions 29 profileUseOtherFlags = []string{"-Wno-backend-plugin"} 30 31 globalPgoProfileProjects = []string{ 32 "toolchain/pgo-profiles", 33 "vendor/google_data/pgo-profiles", 34 } 35 ) 36 37 const pgoProfileProjectsConfigKey = "PgoProfileProjects" 38 const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp" 39 const profileSamplingFlag = "-gline-tables-only" 40 const profileUseInstrumentFormat = "-fprofile-use=%s" 41 const profileUseSamplingFormat = "-fprofile-sample-use=%s" 42 43 func getPgoProfileProjects(config android.DeviceConfig) []string { 44 return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string { 45 return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...) 46 }) 47 } 48 49 func recordMissingProfileFile(ctx BaseModuleContext, missing string) { 50 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFile).Store(missing, true) 51 } 52 53 type PgoProperties struct { 54 Pgo struct { 55 Instrumentation *bool 56 Sampling *bool 57 Profile_file *string `android:"arch_variant"` 58 Benchmarks []string 59 Enable_profile_use *bool `android:"arch_variant"` 60 // Additional compiler flags to use when building this module 61 // for profiling (either instrumentation or sampling). 62 Cflags []string `android:"arch_variant"` 63 } `android:"arch_variant"` 64 65 PgoPresent bool `blueprint:"mutated"` 66 ShouldProfileModule bool `blueprint:"mutated"` 67 PgoCompile bool `blueprint:"mutated"` 68 } 69 70 type pgo struct { 71 Properties PgoProperties 72 } 73 74 func (props *PgoProperties) isInstrumentation() bool { 75 return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true 76 } 77 78 func (props *PgoProperties) isSampling() bool { 79 return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true 80 } 81 82 func (pgo *pgo) props() []interface{} { 83 return []interface{}{&pgo.Properties} 84 } 85 86 func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { 87 flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...) 88 89 if props.isInstrumentation() { 90 flags.CFlags = append(flags.CFlags, profileInstrumentFlag) 91 // The profile runtime is added below in deps(). Add the below 92 // flag, which is the only other link-time action performed by 93 // the Clang driver during link. 94 flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime") 95 } 96 if props.isSampling() { 97 flags.CFlags = append(flags.CFlags, profileSamplingFlag) 98 flags.LdFlags = append(flags.LdFlags, profileSamplingFlag) 99 } 100 return flags 101 } 102 103 func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath { 104 profile_file := *props.Pgo.Profile_file 105 106 // Test if the profile_file is present in any of the PGO profile projects 107 for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) { 108 // Bug: http://b/74395273 If the profile_file is unavailable, 109 // use a versioned file named 110 // <profile_file>.<arbitrary-version> when available. This 111 // works around an issue where ccache serves stale cache 112 // entries when the profile file has changed. 113 globPattern := filepath.Join(profileProject, profile_file+".*") 114 versioned_profiles, err := ctx.GlobWithDeps(globPattern, nil) 115 if err != nil { 116 ctx.ModuleErrorf("glob: %s", err.Error()) 117 } 118 119 path := android.ExistentPathForSource(ctx, profileProject, profile_file) 120 if path.Valid() { 121 if len(versioned_profiles) != 0 { 122 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profile_file)+", "+strings.Join(versioned_profiles, ", ")) 123 } 124 return path 125 } 126 127 if len(versioned_profiles) > 1 { 128 ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versioned_profiles, ", ")) 129 } else if len(versioned_profiles) == 1 { 130 return android.OptionalPathForPath(android.PathForSource(ctx, versioned_profiles[0])) 131 } 132 } 133 134 // Record that this module's profile file is absent 135 missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName() 136 recordMissingProfileFile(ctx, missing) 137 138 return android.OptionalPathForPath(nil) 139 } 140 141 func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string { 142 if props.isInstrumentation() { 143 return fmt.Sprintf(profileUseInstrumentFormat, file) 144 } 145 if props.isSampling() { 146 return fmt.Sprintf(profileUseSamplingFormat, file) 147 } 148 return "" 149 } 150 151 func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string { 152 flags := []string{props.profileUseFlag(ctx, file)} 153 flags = append(flags, profileUseOtherFlags...) 154 return flags 155 } 156 157 func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags { 158 // Return if 'pgo' property is not present in this module. 159 if !props.PgoPresent { 160 return flags 161 } 162 163 // Skip -fprofile-use if 'enable_profile_use' property is set 164 if props.Pgo.Enable_profile_use != nil && *props.Pgo.Enable_profile_use == false { 165 return flags 166 } 167 168 // If the profile file is found, add flags to use the profile 169 if profileFile := props.getPgoProfileFile(ctx); profileFile.Valid() { 170 profileFilePath := profileFile.Path() 171 profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String()) 172 173 flags.CFlags = append(flags.CFlags, profileUseFlags...) 174 flags.LdFlags = append(flags.LdFlags, profileUseFlags...) 175 176 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt 177 // if profileFile gets updated 178 flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath) 179 flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath) 180 } 181 return flags 182 } 183 184 func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { 185 isInstrumentation := props.isInstrumentation() 186 isSampling := props.isSampling() 187 188 profileKindPresent := isInstrumentation || isSampling 189 filePresent := props.Pgo.Profile_file != nil 190 benchmarksPresent := len(props.Pgo.Benchmarks) > 0 191 192 // If all three properties are absent, PGO is OFF for this module 193 if !profileKindPresent && !filePresent && !benchmarksPresent { 194 return false 195 } 196 197 // If at least one property exists, validate that all properties exist 198 if !profileKindPresent || !filePresent || !benchmarksPresent { 199 var missing []string 200 if !profileKindPresent { 201 missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)") 202 } 203 if !filePresent { 204 missing = append(missing, "profile_file property") 205 } 206 if !benchmarksPresent { 207 missing = append(missing, "non-empty benchmarks property") 208 } 209 missingProps := strings.Join(missing, ", ") 210 ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps) 211 } 212 213 // Sampling not supported yet 214 if isSampling { 215 ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)") 216 } 217 218 if isSampling && isInstrumentation { 219 ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set") 220 } 221 222 return true 223 } 224 225 func (pgo *pgo) begin(ctx BaseModuleContext) { 226 // TODO Evaluate if we need to support PGO for host modules 227 if ctx.Host() { 228 return 229 } 230 231 // Check if PGO is needed for this module 232 pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx) 233 234 if !pgo.Properties.PgoPresent { 235 return 236 } 237 238 // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set 239 // and includes 'all', 'ALL' or a benchmark listed for this module. 240 // 241 // TODO Validate that each benchmark instruments at least one module 242 pgo.Properties.ShouldProfileModule = false 243 pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT") 244 pgoBenchmarksMap := make(map[string]bool) 245 for _, b := range strings.Split(pgoBenchmarks, ",") { 246 pgoBenchmarksMap[b] = true 247 } 248 249 if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true { 250 pgo.Properties.ShouldProfileModule = true 251 } else { 252 for _, b := range pgo.Properties.Pgo.Benchmarks { 253 if pgoBenchmarksMap[b] == true { 254 pgo.Properties.ShouldProfileModule = true 255 break 256 } 257 } 258 } 259 260 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { 261 if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() { 262 pgo.Properties.PgoCompile = true 263 } 264 } 265 } 266 267 func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps { 268 if pgo.Properties.ShouldProfileModule { 269 runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain()) 270 deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary) 271 } 272 return deps 273 } 274 275 func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { 276 if ctx.Host() { 277 return flags 278 } 279 280 props := pgo.Properties 281 282 // Add flags to profile this module based on its profile_kind 283 if props.ShouldProfileModule { 284 return props.addProfileGatherFlags(ctx, flags) 285 } 286 287 if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { 288 return props.addProfileUseFlags(ctx, flags) 289 } 290 291 return flags 292 }