aboutsummaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorPirama Arumuga Nainar <pirama@google.com>2017-08-31 23:38:27 -0700
committerPirama Arumuga Nainar <pirama@google.com>2017-09-21 12:37:19 -0700
commitada83ec0a6dc677cffd0d29c10b48cbda477daf7 (patch)
tree5be48add3d9c89ce7c5b4e615642812f5aa7bb01 /cc
parentd685385c6baf385c1d87bfa92dcd0f824a2cb09f (diff)
downloadbuild_soong-ada83ec0a6dc677cffd0d29c10b48cbda477daf7.tar.gz
build_soong-ada83ec0a6dc677cffd0d29c10b48cbda477daf7.tar.bz2
build_soong-ada83ec0a6dc677cffd0d29c10b48cbda477daf7.zip
Add PGO support to soong
Bug: http://b/63768402 Bug: http://b/65598278 Add support for the 'pgo' property to specify how a module is processed under PGO. A sample property is below: pgo: { instrumentation: true, // could be "sampling: true" when supported profile_file: "pgo_simple.profdata", benchmarks: ["pgo_simple"], } 1. Runtime profiles can be gathered using "sampling" or "instrumentation". Sampling is not supported initially. 2. If 'toolchain/pgo-profiles' project is found, 'toolchain/pgo-profiles/${profile_file}' is passed to the compiler and linker when building this module. 3. If ANDROID_PGO_INSTRUMENT environment variable is set, and includes a benchmark in the 'benchmarks' list, appropriate flags (for e.g. -fprofile-generate for instrumentation) are passed to the compiler and linker when building this module. Test: Add example modules that specify the pgo property and verify appropriate flags and dependencies in the Ninja file. Some tests/examples are in https://android-review.googlesource.com/474805 Change-Id: I6242e0c904497a115e367dea6927ba1c4b906355
Diffstat (limited to 'cc')
-rw-r--r--cc/binary.go1
-rw-r--r--cc/cc.go15
-rw-r--r--cc/library.go2
-rw-r--r--cc/pgo.go190
4 files changed, 206 insertions, 2 deletions
diff --git a/cc/binary.go b/cc/binary.go
index 4b10070f..b2405b6f 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -325,6 +325,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext,
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
linkerDeps = append(linkerDeps, objs.tidyFiles...)
+ linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
diff --git a/cc/cc.go b/cc/cc.go
index af58f9d0..b4b70ed5 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -134,7 +134,8 @@ type Flags struct {
RequiredInstructionSet string
DynamicLinker string
- CFlagsDeps android.Paths // Files depended on by compiler flags
+ CFlagsDeps android.Paths // Files depended on by compiler flags
+ LdFlagsDeps android.Paths // Files depended on by linker flags
GroupStaticLibs bool
}
@@ -308,6 +309,7 @@ type Module struct {
sabi *sabi
vndkdep *vndkdep
lto *lto
+ pgo *pgo
androidMkSharedLibDeps []string
@@ -350,6 +352,9 @@ func (c *Module) Init() android.Module {
if c.lto != nil {
c.AddProperties(c.lto.props()...)
}
+ if c.pgo != nil {
+ c.AddProperties(c.pgo.props()...)
+ }
for _, feature := range c.features {
c.AddProperties(feature.props()...)
}
@@ -506,6 +511,7 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo
module.sabi = &sabi{}
module.vndkdep = &vndkdep{}
module.lto = &lto{}
+ module.pgo = &pgo{}
return module
}
@@ -557,6 +563,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
if c.lto != nil {
flags = c.lto.flags(ctx, flags)
}
+ if c.pgo != nil {
+ flags = c.pgo.flags(ctx, flags)
+ }
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
@@ -643,6 +652,9 @@ func (c *Module) begin(ctx BaseModuleContext) {
if c.lto != nil {
c.lto.begin(ctx)
}
+ if c.pgo != nil {
+ c.pgo.begin(ctx)
+ }
for _, feature := range c.features {
feature.begin(ctx)
}
@@ -1250,6 +1262,7 @@ func DefaultsFactory(props ...interface{}) android.Module {
&SAbiProperties{},
&VndkProperties{},
&LTOProperties{},
+ &PgoProperties{},
)
android.InitDefaultsModule(module)
diff --git a/cc/library.go b/cc/library.go
index 2a866dc9..f1681db2 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -484,6 +484,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
var linkerDeps android.Paths
+ linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
versionScript := android.OptionalPathForModuleSrc(ctx, library.Properties.Version_script)
unexportedSymbols := android.OptionalPathForModuleSrc(ctx, library.Properties.Unexported_symbols_list)
@@ -628,7 +629,6 @@ func (library *libraryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
objs = objs.Append(deps.Objs)
-
var out android.Path
if library.static() || library.header() {
out = library.linkStatic(ctx, flags, deps, objs)
diff --git a/cc/pgo.go b/cc/pgo.go
new file mode 100644
index 00000000..ccddece9
--- /dev/null
+++ b/cc/pgo.go
@@ -0,0 +1,190 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "fmt"
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ // Add flags to ignore warnings that profiles are old or missing for
+ // some functions
+ profileUseOtherFlags = []string{}
+)
+
+const pgoProfileProject = "toolchain/pgo-profiles"
+
+const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
+const profileSamplingFlag = "-gline-tables-only"
+const profileUseInstrumentFormat = "-fprofile-use=%s"
+const profileUseSamplingFormat = "-fprofile-sample-use=%s"
+
+type PgoProperties struct {
+ Pgo struct {
+ Instrumentation *bool
+ Sampling *bool
+ Profile_file *string `android:"arch_variant"`
+ Benchmarks []string
+ } `android:"arch_variant"`
+
+ PgoPresent bool `blueprint:"mutated"`
+ ShouldProfileModule bool `blueprint:"mutated"`
+}
+
+type pgo struct {
+ Properties PgoProperties
+}
+
+func (pgo *pgo) props() []interface{} {
+ return []interface{}{&pgo.Properties}
+}
+
+func (pgo *pgo) profileGatherFlags(ctx ModuleContext) string {
+ if *pgo.Properties.Pgo.Instrumentation {
+ return profileInstrumentFlag
+ }
+ if *pgo.Properties.Pgo.Sampling {
+ return profileSamplingFlag
+ }
+ return ""
+}
+
+func (pgo *pgo) profileUseFlag(ctx ModuleContext, file string) string {
+ if *pgo.Properties.Pgo.Instrumentation {
+ return fmt.Sprintf(profileUseInstrumentFormat, file)
+ }
+ if *pgo.Properties.Pgo.Sampling {
+ return fmt.Sprintf(profileUseSamplingFormat, file)
+ }
+ return ""
+}
+
+func (pgo *pgo) profileUseFlags(ctx ModuleContext, file string) []string {
+ flags := []string{pgo.profileUseFlag(ctx, file)}
+ flags = append(flags, profileUseOtherFlags...)
+ return flags
+}
+
+func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
+ isInstrumentation := props.Pgo.Instrumentation != nil
+ isSampling := props.Pgo.Sampling != nil
+
+ profileKindPresent := isInstrumentation || isSampling
+ filePresent := props.Pgo.Profile_file != nil
+ benchmarksPresent := len(props.Pgo.Benchmarks) > 0
+
+ // If all three properties are absent, PGO is OFF for this module
+ if !profileKindPresent && !filePresent && !benchmarksPresent {
+ return false
+ }
+
+ // If at least one property exists, validate that all properties exist
+ if !profileKindPresent || !filePresent || !benchmarksPresent {
+ var missing []string
+ if !profileKindPresent {
+ missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
+ }
+ if !filePresent {
+ missing = append(missing, "profile_file property")
+ }
+ if !benchmarksPresent {
+ missing = append(missing, "non-empty benchmarks property")
+ }
+ missingProps := strings.Join(missing, ", ")
+ ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
+ }
+
+ // Sampling not supported yet
+ //
+ // TODO When sampling support is turned on, check that instrumentation and
+ // sampling are not simultaneously specified
+ if isSampling {
+ ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)")
+ }
+
+ return true
+}
+
+func getPgoProfilesDir(ctx ModuleContext) android.OptionalPath {
+ return android.ExistentPathForSource(ctx, "", pgoProfileProject)
+}
+
+func (pgo *pgo) begin(ctx BaseModuleContext) {
+ // TODO Evaluate if we need to support PGO for host modules
+ if ctx.Host() {
+ return
+ }
+
+ // Check if PGO is needed for this module
+ pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
+
+ if !pgo.Properties.PgoPresent {
+ return
+ }
+
+ // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
+ // and includes a benchmark listed for this module
+ //
+ // TODO Validate that each benchmark instruments at least one module
+ pgo.Properties.ShouldProfileModule = false
+ pgoBenchmarks := ctx.AConfig().Getenv("ANDROID_PGO_INSTRUMENT")
+ pgoBenchmarksMap := make(map[string]bool)
+ for _, b := range strings.Split(pgoBenchmarks, ",") {
+ pgoBenchmarksMap[b] = true
+ }
+
+ for _, b := range pgo.Properties.Pgo.Benchmarks {
+ if pgoBenchmarksMap[b] == true {
+ pgo.Properties.ShouldProfileModule = true
+ break
+ }
+ }
+}
+
+func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
+ if ctx.Host() {
+ return flags
+ }
+
+ props := pgo.Properties
+
+ // Add flags to profile this module based on its profile_kind
+ if props.ShouldProfileModule {
+ profileGatherFlags := pgo.profileGatherFlags(ctx)
+ flags.LdFlags = append(flags.LdFlags, profileGatherFlags)
+ flags.CFlags = append(flags.CFlags, profileGatherFlags)
+ return flags
+ }
+
+ // If the PGO profiles project is found, and this module has PGO
+ // enabled, add flags to use the profile
+ if profilesDir := getPgoProfilesDir(ctx); props.PgoPresent && profilesDir.Valid() {
+ profileFile := android.PathForSource(ctx, profilesDir.String(), *(props.Pgo.Profile_file))
+ profileUseFlags := pgo.profileUseFlags(ctx, profileFile.String())
+
+ flags.CFlags = append(flags.CFlags, profileUseFlags...)
+ flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
+
+ // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+ // if profileFile gets updated
+ flags.CFlagsDeps = append(flags.CFlagsDeps, profileFile)
+ flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFile)
+ }
+
+ return flags
+}