From 7e53c57ed6a42dc096971270797e888fefe206a8 Mon Sep 17 00:00:00 2001 From: Yi Kong Date: Wed, 14 Feb 2018 18:16:12 +0800 Subject: [PATCH] Disable inlining and loop unrolling in LTO without PGO profile Such optimisations may significantly increase the binary size when compiler heuristics are off. Disabling these helps cut down the binary sizes with negligible decrease in performance, but allows us to be more comfortable enabling LTO across various projects. Test: m Test: dex2oat, hwui, skia benchmark Bug: 62839002 Change-Id: Id63e8dd295df2972f76ae4e29ee367080fff8429 --- cc/cc.go | 12 ++++++++++++ cc/lto.go | 7 +++++++ cc/pgo.go | 11 +++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cc/cc.go b/cc/cc.go index 49fefe965..f65441fa6 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -211,6 +211,7 @@ type ModuleContextIntf interface { selectedStl() string baseModuleName() string getVndkExtendsModuleName() string + isPgoCompile() bool } type ModuleContext interface { @@ -408,6 +409,13 @@ func (c *Module) isVndk() bool { return false } +func (c *Module) isPgoCompile() bool { + if pgo := c.pgo; pgo != nil { + return pgo.Properties.PgoCompile + } + return false +} + func (c *Module) isVndkSp() bool { if vndkdep := c.vndkdep; vndkdep != nil { return vndkdep.isVndkSp() @@ -507,6 +515,10 @@ func (ctx *moduleContextImpl) isVndk() bool { return ctx.mod.isVndk() } +func (ctx *moduleContextImpl) isPgoCompile() bool { + return ctx.mod.isPgoCompile() +} + func (ctx *moduleContextImpl) isVndkSp() bool { return ctx.mod.isVndkSp() } diff --git a/cc/lto.go b/cc/lto.go index 4757fc7e8..2ced12418 100644 --- a/cc/lto.go +++ b/cc/lto.go @@ -87,6 +87,13 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls") } flags.ArGoldPlugin = true + + // If the module does not have a profile, be conservative and do not inline + // or unroll loops during LTO, in order to prevent significant size bloat. + if !ctx.isPgoCompile() { + flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0") + flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0") + } } return flags } diff --git a/cc/pgo.go b/cc/pgo.go index 1e7033979..779ef39de 100644 --- a/cc/pgo.go +++ b/cc/pgo.go @@ -45,7 +45,7 @@ func getPgoProfileProjects(config android.DeviceConfig) []string { }) } -func recordMissingProfileFile(ctx ModuleContext, missing string) { +func recordMissingProfileFile(ctx BaseModuleContext, missing string) { getNamedMapForConfig(ctx.Config(), modulesMissingProfileFile).Store(missing, true) } @@ -63,6 +63,7 @@ type PgoProperties struct { PgoPresent bool `blueprint:"mutated"` ShouldProfileModule bool `blueprint:"mutated"` + PgoCompile bool `blueprint:"mutated"` } type pgo struct { @@ -98,7 +99,7 @@ func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags return flags } -func (props *PgoProperties) getPgoProfileFile(ctx ModuleContext) android.OptionalPath { +func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath { // Test if the profile_file is present in any of the PGO profile projects for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) { path := android.ExistentPathForSource(ctx, "", profileProject, *props.Pgo.Profile_file) @@ -232,6 +233,12 @@ func (pgo *pgo) begin(ctx BaseModuleContext) { } } } + + if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { + if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() { + pgo.Properties.PgoCompile = true + } + } } func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps {