blob: 6e08da7a00627b966501a7f170fb10c5a921527e [file] [log] [blame]
Sharjeel Khanc6a93d82023-07-18 21:01:11 +00001// Copyright 2023 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// Note: If you want to know how to use orderfile for your binary or shared
16// library, you can go look at the README in toolchains/pgo-profiles/orderfiles
17
18package cc
19
20import (
21 "fmt"
22
Colin Cross33e0c812024-01-23 16:36:07 -080023 "github.com/google/blueprint"
24
Sharjeel Khanc6a93d82023-07-18 21:01:11 +000025 "android/soong/android"
26)
27
28// Order files are text files containing symbols representing functions names.
29// Linkers (lld) uses order files to layout functions in a specific order.
30// These binaries with ordered symbols will reduce page faults and improve a program's launch time
31// due to the efficient loading of symbols during a program’s cold-start.
32var (
33 // Add flags to ignore warnings about symbols not be found
34 // or not allowed to be ordered
35 orderfileOtherFlags = []string{
36 "-Wl,--no-warn-symbol-ordering",
37 }
38
39 // Add folder projects for orderfiles
40 globalOrderfileProjects = []string{
41 "toolchain/pgo-profiles/orderfiles",
42 "vendor/google_data/pgo_profile/orderfiles",
43 }
44)
45
46var orderfileProjectsConfigKey = android.NewOnceKey("OrderfileProjects")
47
48const orderfileProfileFlag = "-forder-file-instrumentation"
49const orderfileUseFormat = "-Wl,--symbol-ordering-file=%s"
50
51func getOrderfileProjects(config android.DeviceConfig) []string {
52 return config.OnceStringSlice(orderfileProjectsConfigKey, func() []string {
53 return globalOrderfileProjects
54 })
55}
56
Sharjeel Khanc6a93d82023-07-18 21:01:11 +000057type OrderfileProperties struct {
58 Orderfile struct {
Cole Faust06ea5312023-10-18 17:38:40 -070059 Instrumentation *bool
60 Order_file_path *string `android:"arch_variant"`
61 Load_order_file *bool `android:"arch_variant"`
Sharjeel Khanc6a93d82023-07-18 21:01:11 +000062 // Additional compiler flags to use when building this module
63 // for orderfile profiling.
64 Cflags []string `android:"arch_variant"`
65 } `android:"arch_variant"`
66
Cole Faust06ea5312023-10-18 17:38:40 -070067 ShouldProfileModule bool `blueprint:"mutated"`
68 OrderfileLoad bool `blueprint:"mutated"`
69 OrderfileInstrLink bool `blueprint:"mutated"`
Sharjeel Khanc6a93d82023-07-18 21:01:11 +000070}
71
72type orderfile struct {
73 Properties OrderfileProperties
74}
75
76func (props *OrderfileProperties) shouldInstrument() bool {
77 return Bool(props.Orderfile.Instrumentation)
78}
79
80// ShouldLoadOrderfile returns true if we need to load the order file rather than
81// profile the binary or shared library
82func (props *OrderfileProperties) shouldLoadOrderfile() bool {
83 return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil
84}
85
86// orderfileEnabled returns true for binaries and shared libraries
87// if instrument flag is set to true
88func (orderfile *orderfile) orderfileEnabled() bool {
89 return orderfile != nil && orderfile.Properties.shouldInstrument()
90}
91
92// orderfileLinkEnabled returns true for binaries and shared libraries
93// if you should instrument dependencies
94func (orderfile *orderfile) orderfileLinkEnabled() bool {
95 return orderfile != nil && orderfile.Properties.OrderfileInstrLink
96}
97
98func (orderfile *orderfile) props() []interface{} {
99 return []interface{}{&orderfile.Properties}
100}
101
102// Get the path to the order file by checking it is valid and not empty
103func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath {
104 orderFile := *props.Orderfile.Order_file_path
105
106 // Test if the order file is present in any of the Orderfile projects
107 for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) {
108 path := android.ExistentPathForSource(ctx, profileProject, orderFile)
109 if path.Valid() {
110 return path
111 }
112 }
113
114 // Record that this module's order file is absent
115 missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
Yu Liu76d94462024-10-31 23:32:36 +0000116 ctx.getOrCreateMakeVarsInfo().MissingProfile = missing
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000117
118 return android.OptionalPath{}
119}
120
121func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000122 flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag)
123 flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation")
Sharjeel Khan3c5d4c22023-08-11 18:13:38 +0000124 flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000125 flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag)
126 return flags
127}
128
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000129func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string {
130 flags := []string{fmt.Sprintf(orderfileUseFormat, file)}
131 flags = append(flags, orderfileOtherFlags...)
132 return flags
133}
134
135func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags {
136 orderFile := props.getOrderfile(ctx)
137 orderFilePath := orderFile.Path()
138 loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
139
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000140 flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
141
142 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
143 // if orderfile gets updated
144 flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath)
145 flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath)
146 return flags
147}
148
149func (orderfile *orderfile) begin(ctx BaseModuleContext) {
150 // Currently, we are not enabling orderfiles for host
151 if ctx.Host() {
152 return
153 }
154
155 // Currently, we are not enabling orderfiles to begin from static libraries
156 if ctx.static() && !ctx.staticBinary() {
157 return
158 }
159
160 if ctx.DeviceConfig().ClangCoverageEnabled() {
161 return
162 }
163
164 // Checking if orderfile is enabled for this module
165 if !orderfile.orderfileEnabled() {
166 return
167 }
168
169 orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile()
170 orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile()
171 orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile()
172}
173
174func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags {
175 props := orderfile.Properties
176 // Add flags to load the orderfile using the path in its Android.bp
177 if orderfile.Properties.OrderfileLoad {
178 flags = props.addLoadFlags(ctx, flags)
179 return flags
180 }
181
182 // Add flags to profile this module
183 if props.ShouldProfileModule {
184 flags = props.addInstrumentationProfileGatherFlags(ctx, flags)
185 return flags
186 }
187
188 return flags
189}
190
Colin Cross33e0c812024-01-23 16:36:07 -0800191func orderfilePropagateViaDepTag(tag blueprint.DependencyTag) bool {
192 libTag, isLibTag := tag.(libraryDependencyTag)
193 // Do not recurse down non-static dependencies
194 if isLibTag {
195 return libTag.static()
196 } else {
197 return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000198 }
199}
200
Colin Cross33e0c812024-01-23 16:36:07 -0800201// orderfileTransitionMutator creates orderfile variants of cc modules.
202type orderfileTransitionMutator struct{}
203
204const ORDERFILE_VARIATION = "orderfile"
205
206func (o *orderfileTransitionMutator) Split(ctx android.BaseModuleContext) []string {
207 return []string{""}
208}
209
210func (o *orderfileTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
211 if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil {
212 if !orderfilePropagateViaDepTag(ctx.DepTag()) {
213 return ""
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000214 }
215
Colin Cross33e0c812024-01-23 16:36:07 -0800216 if sourceVariation != "" {
217 return sourceVariation
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000218 }
219
Colin Cross33e0c812024-01-23 16:36:07 -0800220 // Propagate profile orderfile flags down from binaries and shared libraries
221 if m.orderfile.orderfileLinkEnabled() {
222 return ORDERFILE_VARIATION
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000223 }
224 }
Colin Cross33e0c812024-01-23 16:36:07 -0800225 return ""
226}
227
228func (o *orderfileTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
229 if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil {
230 return incomingVariation
231 }
232 return ""
233}
234
235func (o *orderfileTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
236 if variation == "" {
237 return
238 }
239
240 if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil {
241 m.Properties.PreventInstall = true
242 m.Properties.HideFromMake = true
243 m.orderfile.Properties.ShouldProfileModule = true
244 // We do not allow propagation for load flags because the orderfile is specific
245 // to the module (binary / shared library)
246 m.orderfile.Properties.OrderfileLoad = false
247 }
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000248}