xref: /aosp_15_r20/build/soong/cc/afdo.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2021 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage cc
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"strings"
20*333d2b36SAndroid Build Coastguard Worker
21*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
24*333d2b36SAndroid Build Coastguard Worker)
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Worker// This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering
27*333d2b36SAndroid Build Coastguard Workerconst afdoFlagsFormat = "-fprofile-sample-use=%s -fprofile-sample-accurate"
28*333d2b36SAndroid Build Coastguard Worker
29*333d2b36SAndroid Build Coastguard Workertype AfdoProperties struct {
30*333d2b36SAndroid Build Coastguard Worker	// Afdo allows developers self-service enroll for
31*333d2b36SAndroid Build Coastguard Worker	// automatic feedback-directed optimization using profile data.
32*333d2b36SAndroid Build Coastguard Worker	Afdo bool
33*333d2b36SAndroid Build Coastguard Worker
34*333d2b36SAndroid Build Coastguard Worker	AfdoDep bool `blueprint:"mutated"`
35*333d2b36SAndroid Build Coastguard Worker}
36*333d2b36SAndroid Build Coastguard Worker
37*333d2b36SAndroid Build Coastguard Workertype afdo struct {
38*333d2b36SAndroid Build Coastguard Worker	Properties AfdoProperties
39*333d2b36SAndroid Build Coastguard Worker}
40*333d2b36SAndroid Build Coastguard Worker
41*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) props() []interface{} {
42*333d2b36SAndroid Build Coastguard Worker	return []interface{}{&afdo.Properties}
43*333d2b36SAndroid Build Coastguard Worker}
44*333d2b36SAndroid Build Coastguard Worker
45*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) begin(ctx BaseModuleContext) {
46*333d2b36SAndroid Build Coastguard Worker	// Disable on eng builds for faster build.
47*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().Eng() {
48*333d2b36SAndroid Build Coastguard Worker		afdo.Properties.Afdo = false
49*333d2b36SAndroid Build Coastguard Worker	}
50*333d2b36SAndroid Build Coastguard Worker	// Disable for native coverage builds.
51*333d2b36SAndroid Build Coastguard Worker	if ctx.DeviceConfig().NativeCoverageEnabled() {
52*333d2b36SAndroid Build Coastguard Worker		afdo.Properties.Afdo = false
53*333d2b36SAndroid Build Coastguard Worker	}
54*333d2b36SAndroid Build Coastguard Worker}
55*333d2b36SAndroid Build Coastguard Worker
56*333d2b36SAndroid Build Coastguard Worker// afdoEnabled returns true for binaries and shared libraries
57*333d2b36SAndroid Build Coastguard Worker// that set afdo prop to True.
58*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) afdoEnabled() bool {
59*333d2b36SAndroid Build Coastguard Worker	return afdo != nil && afdo.Properties.Afdo
60*333d2b36SAndroid Build Coastguard Worker}
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) isAfdoCompile(ctx ModuleContext) bool {
63*333d2b36SAndroid Build Coastguard Worker	fdoProfilePath := getFdoProfilePathFromDep(ctx)
64*333d2b36SAndroid Build Coastguard Worker	return !ctx.Host() && (afdo.Properties.Afdo || afdo.Properties.AfdoDep) && (fdoProfilePath != "")
65*333d2b36SAndroid Build Coastguard Worker}
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Workerfunc getFdoProfilePathFromDep(ctx ModuleContext) string {
68*333d2b36SAndroid Build Coastguard Worker	fdoProfileDeps := ctx.GetDirectDepsWithTag(FdoProfileTag)
69*333d2b36SAndroid Build Coastguard Worker	if len(fdoProfileDeps) > 0 && fdoProfileDeps[0] != nil {
70*333d2b36SAndroid Build Coastguard Worker		if info, ok := android.OtherModuleProvider(ctx, fdoProfileDeps[0], FdoProfileProvider); ok {
71*333d2b36SAndroid Build Coastguard Worker			return info.Path.String()
72*333d2b36SAndroid Build Coastguard Worker		}
73*333d2b36SAndroid Build Coastguard Worker	}
74*333d2b36SAndroid Build Coastguard Worker	return ""
75*333d2b36SAndroid Build Coastguard Worker}
76*333d2b36SAndroid Build Coastguard Worker
77*333d2b36SAndroid Build Coastguard Workerfunc (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
78*333d2b36SAndroid Build Coastguard Worker	if ctx.Host() {
79*333d2b36SAndroid Build Coastguard Worker		return flags
80*333d2b36SAndroid Build Coastguard Worker	}
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker	if afdo.Properties.Afdo || afdo.Properties.AfdoDep {
83*333d2b36SAndroid Build Coastguard Worker		// Emit additional debug info for AutoFDO
84*333d2b36SAndroid Build Coastguard Worker		flags.Local.CFlags = append([]string{"-fdebug-info-for-profiling"}, flags.Local.CFlags...)
85*333d2b36SAndroid Build Coastguard Worker		// We use `-funique-internal-linkage-names` to associate profiles to the right internal
86*333d2b36SAndroid Build Coastguard Worker		// functions. This option should be used before generating a profile. Because a profile
87*333d2b36SAndroid Build Coastguard Worker		// generated for a binary without unique names doesn't work well building a binary with
88*333d2b36SAndroid Build Coastguard Worker		// unique names (they have different internal function names).
89*333d2b36SAndroid Build Coastguard Worker		// To avoid a chicken-and-egg problem, we enable `-funique-internal-linkage-names` when
90*333d2b36SAndroid Build Coastguard Worker		// `afdo=true`, whether a profile exists or not.
91*333d2b36SAndroid Build Coastguard Worker		// The profile can take effect in three steps:
92*333d2b36SAndroid Build Coastguard Worker		// 1. Add `afdo: true` in Android.bp, and build the binary.
93*333d2b36SAndroid Build Coastguard Worker		// 2. Collect an AutoFDO profile for the binary.
94*333d2b36SAndroid Build Coastguard Worker		// 3. Make the profile searchable by the build system. So it's used the next time the binary
95*333d2b36SAndroid Build Coastguard Worker		//	  is built.
96*333d2b36SAndroid Build Coastguard Worker		flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...)
97*333d2b36SAndroid Build Coastguard Worker		// Flags for Flow Sensitive AutoFDO
98*333d2b36SAndroid Build Coastguard Worker		flags.Local.CFlags = append([]string{"-mllvm", "-enable-fs-discriminator=true"}, flags.Local.CFlags...)
99*333d2b36SAndroid Build Coastguard Worker		// TODO(b/266595187): Remove the following feature once it is enabled in LLVM by default.
100*333d2b36SAndroid Build Coastguard Worker		flags.Local.CFlags = append([]string{"-mllvm", "-improved-fs-discriminator=true"}, flags.Local.CFlags...)
101*333d2b36SAndroid Build Coastguard Worker	}
102*333d2b36SAndroid Build Coastguard Worker	if fdoProfilePath := getFdoProfilePathFromDep(ctx); fdoProfilePath != "" {
103*333d2b36SAndroid Build Coastguard Worker		// The flags are prepended to allow overriding.
104*333d2b36SAndroid Build Coastguard Worker		profileUseFlag := fmt.Sprintf(afdoFlagsFormat, fdoProfilePath)
105*333d2b36SAndroid Build Coastguard Worker		flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...)
106*333d2b36SAndroid Build Coastguard Worker		flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...)
107*333d2b36SAndroid Build Coastguard Worker
108*333d2b36SAndroid Build Coastguard Worker		// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
109*333d2b36SAndroid Build Coastguard Worker		// if profileFile gets updated
110*333d2b36SAndroid Build Coastguard Worker		pathForSrc := android.PathForSource(ctx, fdoProfilePath)
111*333d2b36SAndroid Build Coastguard Worker		flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc)
112*333d2b36SAndroid Build Coastguard Worker		flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc)
113*333d2b36SAndroid Build Coastguard Worker	}
114*333d2b36SAndroid Build Coastguard Worker
115*333d2b36SAndroid Build Coastguard Worker	return flags
116*333d2b36SAndroid Build Coastguard Worker}
117*333d2b36SAndroid Build Coastguard Worker
118*333d2b36SAndroid Build Coastguard Workerfunc (a *afdo) addDep(ctx android.BottomUpMutatorContext, fdoProfileTarget string) {
119*333d2b36SAndroid Build Coastguard Worker	if fdoProfileName, err := ctx.DeviceConfig().AfdoProfile(fdoProfileTarget); fdoProfileName != "" && err == nil {
120*333d2b36SAndroid Build Coastguard Worker		ctx.AddFarVariationDependencies(
121*333d2b36SAndroid Build Coastguard Worker			[]blueprint.Variation{
122*333d2b36SAndroid Build Coastguard Worker				{Mutator: "arch", Variation: ctx.Target().ArchVariation()},
123*333d2b36SAndroid Build Coastguard Worker				{Mutator: "os", Variation: "android"},
124*333d2b36SAndroid Build Coastguard Worker			},
125*333d2b36SAndroid Build Coastguard Worker			FdoProfileTag,
126*333d2b36SAndroid Build Coastguard Worker			fdoProfileName)
127*333d2b36SAndroid Build Coastguard Worker	}
128*333d2b36SAndroid Build Coastguard Worker}
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Workerfunc afdoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
131*333d2b36SAndroid Build Coastguard Worker	libTag, isLibTag := tag.(libraryDependencyTag)
132*333d2b36SAndroid Build Coastguard Worker	// Do not recurse down non-static dependencies
133*333d2b36SAndroid Build Coastguard Worker	if isLibTag {
134*333d2b36SAndroid Build Coastguard Worker		return libTag.static()
135*333d2b36SAndroid Build Coastguard Worker	} else {
136*333d2b36SAndroid Build Coastguard Worker		return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
137*333d2b36SAndroid Build Coastguard Worker	}
138*333d2b36SAndroid Build Coastguard Worker}
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard Worker// afdoTransitionMutator creates afdo variants of cc modules.
141*333d2b36SAndroid Build Coastguard Workertype afdoTransitionMutator struct{}
142*333d2b36SAndroid Build Coastguard Worker
143*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
144*333d2b36SAndroid Build Coastguard Worker	return []string{""}
145*333d2b36SAndroid Build Coastguard Worker}
146*333d2b36SAndroid Build Coastguard Worker
147*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
148*333d2b36SAndroid Build Coastguard Worker	if ctx.Host() {
149*333d2b36SAndroid Build Coastguard Worker		return ""
150*333d2b36SAndroid Build Coastguard Worker	}
151*333d2b36SAndroid Build Coastguard Worker
152*333d2b36SAndroid Build Coastguard Worker	if m, ok := ctx.Module().(*Module); ok && m.afdo != nil {
153*333d2b36SAndroid Build Coastguard Worker		if !afdoPropagateViaDepTag(ctx.DepTag()) {
154*333d2b36SAndroid Build Coastguard Worker			return ""
155*333d2b36SAndroid Build Coastguard Worker		}
156*333d2b36SAndroid Build Coastguard Worker
157*333d2b36SAndroid Build Coastguard Worker		if sourceVariation != "" {
158*333d2b36SAndroid Build Coastguard Worker			return sourceVariation
159*333d2b36SAndroid Build Coastguard Worker		}
160*333d2b36SAndroid Build Coastguard Worker
161*333d2b36SAndroid Build Coastguard Worker		if !m.afdo.afdoEnabled() {
162*333d2b36SAndroid Build Coastguard Worker			return ""
163*333d2b36SAndroid Build Coastguard Worker		}
164*333d2b36SAndroid Build Coastguard Worker
165*333d2b36SAndroid Build Coastguard Worker		// TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but
166*333d2b36SAndroid Build Coastguard Worker		//  it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies.
167*333d2b36SAndroid Build Coastguard Worker		if m.static() {
168*333d2b36SAndroid Build Coastguard Worker			return ""
169*333d2b36SAndroid Build Coastguard Worker		}
170*333d2b36SAndroid Build Coastguard Worker
171*333d2b36SAndroid Build Coastguard Worker		return encodeTarget(ctx.Module().Name())
172*333d2b36SAndroid Build Coastguard Worker	}
173*333d2b36SAndroid Build Coastguard Worker	return ""
174*333d2b36SAndroid Build Coastguard Worker}
175*333d2b36SAndroid Build Coastguard Worker
176*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
177*333d2b36SAndroid Build Coastguard Worker	if m, ok := ctx.Module().(*Module); ok && m.afdo != nil {
178*333d2b36SAndroid Build Coastguard Worker		return incomingVariation
179*333d2b36SAndroid Build Coastguard Worker	}
180*333d2b36SAndroid Build Coastguard Worker	return ""
181*333d2b36SAndroid Build Coastguard Worker}
182*333d2b36SAndroid Build Coastguard Worker
183*333d2b36SAndroid Build Coastguard Workerfunc (a *afdoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
184*333d2b36SAndroid Build Coastguard Worker	if m, ok := ctx.Module().(*Module); ok && m.afdo != nil {
185*333d2b36SAndroid Build Coastguard Worker		if !m.Enabled(ctx) {
186*333d2b36SAndroid Build Coastguard Worker			return
187*333d2b36SAndroid Build Coastguard Worker		}
188*333d2b36SAndroid Build Coastguard Worker		if variation == "" {
189*333d2b36SAndroid Build Coastguard Worker			// The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO
190*333d2b36SAndroid Build Coastguard Worker			// variant of a dependency.
191*333d2b36SAndroid Build Coastguard Worker			if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() {
192*333d2b36SAndroid Build Coastguard Worker				m.afdo.addDep(ctx, ctx.ModuleName())
193*333d2b36SAndroid Build Coastguard Worker			}
194*333d2b36SAndroid Build Coastguard Worker		} else {
195*333d2b36SAndroid Build Coastguard Worker			// The non-empty variation is the AFDO variant of a dependency of a module that enabled AFDO
196*333d2b36SAndroid Build Coastguard Worker			// for itself.
197*333d2b36SAndroid Build Coastguard Worker			m.Properties.PreventInstall = true
198*333d2b36SAndroid Build Coastguard Worker			m.Properties.HideFromMake = true
199*333d2b36SAndroid Build Coastguard Worker			m.afdo.Properties.AfdoDep = true
200*333d2b36SAndroid Build Coastguard Worker			m.afdo.addDep(ctx, decodeTarget(variation))
201*333d2b36SAndroid Build Coastguard Worker		}
202*333d2b36SAndroid Build Coastguard Worker	}
203*333d2b36SAndroid Build Coastguard Worker}
204*333d2b36SAndroid Build Coastguard Worker
205*333d2b36SAndroid Build Coastguard Worker// Encode target name to variation name.
206*333d2b36SAndroid Build Coastguard Workerfunc encodeTarget(target string) string {
207*333d2b36SAndroid Build Coastguard Worker	if target == "" {
208*333d2b36SAndroid Build Coastguard Worker		return ""
209*333d2b36SAndroid Build Coastguard Worker	}
210*333d2b36SAndroid Build Coastguard Worker	return "afdo-" + target
211*333d2b36SAndroid Build Coastguard Worker}
212*333d2b36SAndroid Build Coastguard Worker
213*333d2b36SAndroid Build Coastguard Worker// Decode target name from variation name.
214*333d2b36SAndroid Build Coastguard Workerfunc decodeTarget(variation string) string {
215*333d2b36SAndroid Build Coastguard Worker	if variation == "" {
216*333d2b36SAndroid Build Coastguard Worker		return ""
217*333d2b36SAndroid Build Coastguard Worker	}
218*333d2b36SAndroid Build Coastguard Worker	return strings.TrimPrefix(variation, "afdo-")
219*333d2b36SAndroid Build Coastguard Worker}
220