blob: 9192e8168754688d73dc86637f43e79a4539a2f7 [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
23 "android/soong/android"
24)
25
26// Order files are text files containing symbols representing functions names.
27// Linkers (lld) uses order files to layout functions in a specific order.
28// These binaries with ordered symbols will reduce page faults and improve a program's launch time
29// due to the efficient loading of symbols during a program’s cold-start.
30var (
31 // Add flags to ignore warnings about symbols not be found
32 // or not allowed to be ordered
33 orderfileOtherFlags = []string{
34 "-Wl,--no-warn-symbol-ordering",
35 }
36
37 // Add folder projects for orderfiles
38 globalOrderfileProjects = []string{
39 "toolchain/pgo-profiles/orderfiles",
40 "vendor/google_data/pgo_profile/orderfiles",
41 }
42)
43
44var orderfileProjectsConfigKey = android.NewOnceKey("OrderfileProjects")
45
46const orderfileProfileFlag = "-forder-file-instrumentation"
47const orderfileUseFormat = "-Wl,--symbol-ordering-file=%s"
48
49func getOrderfileProjects(config android.DeviceConfig) []string {
50 return config.OnceStringSlice(orderfileProjectsConfigKey, func() []string {
51 return globalOrderfileProjects
52 })
53}
54
55func recordMissingOrderfile(ctx BaseModuleContext, missing string) {
56 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
57}
58
59type OrderfileProperties struct {
60 Orderfile struct {
Cole Faust06ea5312023-10-18 17:38:40 -070061 Instrumentation *bool
62 Order_file_path *string `android:"arch_variant"`
63 Load_order_file *bool `android:"arch_variant"`
Sharjeel Khanc6a93d82023-07-18 21:01:11 +000064 // Additional compiler flags to use when building this module
65 // for orderfile profiling.
66 Cflags []string `android:"arch_variant"`
67 } `android:"arch_variant"`
68
Cole Faust06ea5312023-10-18 17:38:40 -070069 ShouldProfileModule bool `blueprint:"mutated"`
70 OrderfileLoad bool `blueprint:"mutated"`
71 OrderfileInstrLink bool `blueprint:"mutated"`
Sharjeel Khanc6a93d82023-07-18 21:01:11 +000072}
73
74type orderfile struct {
75 Properties OrderfileProperties
76}
77
78func (props *OrderfileProperties) shouldInstrument() bool {
79 return Bool(props.Orderfile.Instrumentation)
80}
81
82// ShouldLoadOrderfile returns true if we need to load the order file rather than
83// profile the binary or shared library
84func (props *OrderfileProperties) shouldLoadOrderfile() bool {
85 return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil
86}
87
88// orderfileEnabled returns true for binaries and shared libraries
89// if instrument flag is set to true
90func (orderfile *orderfile) orderfileEnabled() bool {
91 return orderfile != nil && orderfile.Properties.shouldInstrument()
92}
93
94// orderfileLinkEnabled returns true for binaries and shared libraries
95// if you should instrument dependencies
96func (orderfile *orderfile) orderfileLinkEnabled() bool {
97 return orderfile != nil && orderfile.Properties.OrderfileInstrLink
98}
99
100func (orderfile *orderfile) props() []interface{} {
101 return []interface{}{&orderfile.Properties}
102}
103
104// Get the path to the order file by checking it is valid and not empty
105func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath {
106 orderFile := *props.Orderfile.Order_file_path
107
108 // Test if the order file is present in any of the Orderfile projects
109 for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) {
110 path := android.ExistentPathForSource(ctx, profileProject, orderFile)
111 if path.Valid() {
112 return path
113 }
114 }
115
116 // Record that this module's order file is absent
117 missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
118 recordMissingOrderfile(ctx, missing)
119
120 return android.OptionalPath{}
121}
122
123func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000124 flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag)
125 flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation")
Sharjeel Khan3c5d4c22023-08-11 18:13:38 +0000126 flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000127 flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag)
128 return flags
129}
130
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000131func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string {
132 flags := []string{fmt.Sprintf(orderfileUseFormat, file)}
133 flags = append(flags, orderfileOtherFlags...)
134 return flags
135}
136
137func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags {
138 orderFile := props.getOrderfile(ctx)
139 orderFilePath := orderFile.Path()
140 loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
141
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000142 flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
143
144 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
145 // if orderfile gets updated
146 flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath)
147 flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath)
148 return flags
149}
150
151func (orderfile *orderfile) begin(ctx BaseModuleContext) {
152 // Currently, we are not enabling orderfiles for host
153 if ctx.Host() {
154 return
155 }
156
157 // Currently, we are not enabling orderfiles to begin from static libraries
158 if ctx.static() && !ctx.staticBinary() {
159 return
160 }
161
162 if ctx.DeviceConfig().ClangCoverageEnabled() {
163 return
164 }
165
166 // Checking if orderfile is enabled for this module
167 if !orderfile.orderfileEnabled() {
168 return
169 }
170
171 orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile()
172 orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile()
173 orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile()
174}
175
176func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags {
177 props := orderfile.Properties
178 // Add flags to load the orderfile using the path in its Android.bp
179 if orderfile.Properties.OrderfileLoad {
180 flags = props.addLoadFlags(ctx, flags)
181 return flags
182 }
183
184 // Add flags to profile this module
185 if props.ShouldProfileModule {
186 flags = props.addInstrumentationProfileGatherFlags(ctx, flags)
187 return flags
188 }
189
190 return flags
191}
192
193// Propagate profile orderfile flags down from binaries and shared libraries
194// We do not allow propagation for load flags because the orderfile is specific
195// to the module (binary / shared library)
196func orderfileDepsMutator(mctx android.TopDownMutatorContext) {
197 if m, ok := mctx.Module().(*Module); ok {
198 if !m.orderfile.orderfileLinkEnabled() {
199 return
200 }
201 mctx.WalkDeps(func(dep android.
202 Module, parent android.Module) bool {
203 tag := mctx.OtherModuleDependencyTag(dep)
204 libTag, isLibTag := tag.(libraryDependencyTag)
205
206 // Do not recurse down non-static dependencies
207 if isLibTag {
208 if !libTag.static() {
209 return false
210 }
211 } else {
212 if tag != objDepTag && tag != reuseObjTag {
213 return false
214 }
215 }
216
217 if dep, ok := dep.(*Module); ok {
218 if m.orderfile.Properties.OrderfileInstrLink {
Cole Faust06ea5312023-10-18 17:38:40 -0700219 dep.orderfile.Properties.OrderfileInstrLink = true
Sharjeel Khanc6a93d82023-07-18 21:01:11 +0000220 }
221 }
222
223 return true
224 })
225 }
226}
227
228// Create orderfile variants for modules that need them
229func orderfileMutator(mctx android.BottomUpMutatorContext) {
230 if m, ok := mctx.Module().(*Module); ok && m.orderfile != nil {
231 if !m.static() && m.orderfile.orderfileEnabled() {
232 mctx.SetDependencyVariation("orderfile")
233 return
234 }
235
236 variationNames := []string{""}
237 if m.orderfile.Properties.OrderfileInstrLink {
238 variationNames = append(variationNames, "orderfile")
239 }
240
241 if len(variationNames) > 1 {
242 modules := mctx.CreateVariations(variationNames...)
243 for i, name := range variationNames {
244 if name == "" {
245 continue
246 }
247 variation := modules[i].(*Module)
248 variation.Properties.PreventInstall = true
249 variation.Properties.HideFromMake = true
250 variation.orderfile.Properties.ShouldProfileModule = true
251 variation.orderfile.Properties.OrderfileLoad = false
252 }
253 }
254 }
255}