1// 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 "github.com/google/blueprint" 24 25 "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 57func recordMissingOrderfile(ctx BaseModuleContext, missing string) { 58 getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true) 59} 60 61type OrderfileProperties struct { 62 Orderfile struct { 63 Instrumentation *bool 64 Order_file_path *string `android:"arch_variant"` 65 Load_order_file *bool `android:"arch_variant"` 66 // Additional compiler flags to use when building this module 67 // for orderfile profiling. 68 Cflags []string `android:"arch_variant"` 69 } `android:"arch_variant"` 70 71 ShouldProfileModule bool `blueprint:"mutated"` 72 OrderfileLoad bool `blueprint:"mutated"` 73 OrderfileInstrLink bool `blueprint:"mutated"` 74} 75 76type orderfile struct { 77 Properties OrderfileProperties 78} 79 80func (props *OrderfileProperties) shouldInstrument() bool { 81 return Bool(props.Orderfile.Instrumentation) 82} 83 84// ShouldLoadOrderfile returns true if we need to load the order file rather than 85// profile the binary or shared library 86func (props *OrderfileProperties) shouldLoadOrderfile() bool { 87 return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil 88} 89 90// orderfileEnabled returns true for binaries and shared libraries 91// if instrument flag is set to true 92func (orderfile *orderfile) orderfileEnabled() bool { 93 return orderfile != nil && orderfile.Properties.shouldInstrument() 94} 95 96// orderfileLinkEnabled returns true for binaries and shared libraries 97// if you should instrument dependencies 98func (orderfile *orderfile) orderfileLinkEnabled() bool { 99 return orderfile != nil && orderfile.Properties.OrderfileInstrLink 100} 101 102func (orderfile *orderfile) props() []interface{} { 103 return []interface{}{&orderfile.Properties} 104} 105 106// Get the path to the order file by checking it is valid and not empty 107func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath { 108 orderFile := *props.Orderfile.Order_file_path 109 110 // Test if the order file is present in any of the Orderfile projects 111 for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) { 112 path := android.ExistentPathForSource(ctx, profileProject, orderFile) 113 if path.Valid() { 114 return path 115 } 116 } 117 118 // Record that this module's order file is absent 119 missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName() 120 recordMissingOrderfile(ctx, missing) 121 122 return android.OptionalPath{} 123} 124 125func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { 126 flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag) 127 flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation") 128 flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...) 129 flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag) 130 return flags 131} 132 133func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string { 134 flags := []string{fmt.Sprintf(orderfileUseFormat, file)} 135 flags = append(flags, orderfileOtherFlags...) 136 return flags 137} 138 139func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags { 140 orderFile := props.getOrderfile(ctx) 141 orderFilePath := orderFile.Path() 142 loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String()) 143 144 flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...) 145 146 // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt 147 // if orderfile gets updated 148 flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath) 149 flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath) 150 return flags 151} 152 153func (orderfile *orderfile) begin(ctx BaseModuleContext) { 154 // Currently, we are not enabling orderfiles for host 155 if ctx.Host() { 156 return 157 } 158 159 // Currently, we are not enabling orderfiles to begin from static libraries 160 if ctx.static() && !ctx.staticBinary() { 161 return 162 } 163 164 if ctx.DeviceConfig().ClangCoverageEnabled() { 165 return 166 } 167 168 // Checking if orderfile is enabled for this module 169 if !orderfile.orderfileEnabled() { 170 return 171 } 172 173 orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile() 174 orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile() 175 orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile() 176} 177 178func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags { 179 props := orderfile.Properties 180 // Add flags to load the orderfile using the path in its Android.bp 181 if orderfile.Properties.OrderfileLoad { 182 flags = props.addLoadFlags(ctx, flags) 183 return flags 184 } 185 186 // Add flags to profile this module 187 if props.ShouldProfileModule { 188 flags = props.addInstrumentationProfileGatherFlags(ctx, flags) 189 return flags 190 } 191 192 return flags 193} 194 195func orderfilePropagateViaDepTag(tag blueprint.DependencyTag) bool { 196 libTag, isLibTag := tag.(libraryDependencyTag) 197 // Do not recurse down non-static dependencies 198 if isLibTag { 199 return libTag.static() 200 } else { 201 return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag 202 } 203} 204 205// orderfileTransitionMutator creates orderfile variants of cc modules. 206type orderfileTransitionMutator struct{} 207 208const ORDERFILE_VARIATION = "orderfile" 209 210func (o *orderfileTransitionMutator) Split(ctx android.BaseModuleContext) []string { 211 return []string{""} 212} 213 214func (o *orderfileTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { 215 if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil { 216 if !orderfilePropagateViaDepTag(ctx.DepTag()) { 217 return "" 218 } 219 220 if sourceVariation != "" { 221 return sourceVariation 222 } 223 224 // Propagate profile orderfile flags down from binaries and shared libraries 225 if m.orderfile.orderfileLinkEnabled() { 226 return ORDERFILE_VARIATION 227 } 228 } 229 return "" 230} 231 232func (o *orderfileTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { 233 if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil { 234 return incomingVariation 235 } 236 return "" 237} 238 239func (o *orderfileTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { 240 if variation == "" { 241 return 242 } 243 244 if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil { 245 m.Properties.PreventInstall = true 246 m.Properties.HideFromMake = true 247 m.orderfile.Properties.ShouldProfileModule = true 248 // We do not allow propagation for load flags because the orderfile is specific 249 // to the module (binary / shared library) 250 m.orderfile.Properties.OrderfileLoad = false 251 } 252} 253