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 57type OrderfileProperties struct { 58 Orderfile struct { 59 Instrumentation *bool 60 Order_file_path *string `android:"arch_variant"` 61 Load_order_file *bool `android:"arch_variant"` 62 // Additional compiler flags to use when building this module 63 // for orderfile profiling. 64 Cflags []string `android:"arch_variant"` 65 } `android:"arch_variant"` 66 67 ShouldProfileModule bool `blueprint:"mutated"` 68 OrderfileLoad bool `blueprint:"mutated"` 69 OrderfileInstrLink bool `blueprint:"mutated"` 70} 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() 116 ctx.getOrCreateMakeVarsInfo().MissingProfile = missing 117 118 return android.OptionalPath{} 119} 120 121func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { 122 flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag) 123 flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation") 124 flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...) 125 flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag) 126 return flags 127} 128 129func (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 140 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 191func 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 198 } 199} 200 201// 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 "" 214 } 215 216 if sourceVariation != "" { 217 return sourceVariation 218 } 219 220 // Propagate profile orderfile flags down from binaries and shared libraries 221 if m.orderfile.orderfileLinkEnabled() { 222 return ORDERFILE_VARIATION 223 } 224 } 225 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 } 248} 249