1*9e965d6fSRomain Jobredeaux# Copyright 2023 The Bazel Authors. All rights reserved. 2*9e965d6fSRomain Jobredeaux# 3*9e965d6fSRomain Jobredeaux# Licensed under the Apache License, Version 2.0 (the "License"); 4*9e965d6fSRomain Jobredeaux# you may not use this file except in compliance with the License. 5*9e965d6fSRomain Jobredeaux# You may obtain a copy of the License at 6*9e965d6fSRomain Jobredeaux# 7*9e965d6fSRomain Jobredeaux# http://www.apache.org/licenses/LICENSE-2.0 8*9e965d6fSRomain Jobredeaux# 9*9e965d6fSRomain Jobredeaux# Unless required by applicable law or agreed to in writing, software 10*9e965d6fSRomain Jobredeaux# distributed under the License is distributed on an "AS IS" BASIS, 11*9e965d6fSRomain Jobredeaux# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9e965d6fSRomain Jobredeaux# See the License for the specific language governing permissions and 13*9e965d6fSRomain Jobredeaux# limitations under the License. 14*9e965d6fSRomain Jobredeaux 15*9e965d6fSRomain Jobredeaux""" 16*9e965d6fSRomain JobredeauxDefines baseline profiles processing methods in Android Rules. 17*9e965d6fSRomain Jobredeaux""" 18*9e965d6fSRomain Jobredeaux 19*9e965d6fSRomain Jobredeaux_BASELINE_PROFILE_DIR_SUFFIX = "-baseline-profile/" 20*9e965d6fSRomain Jobredeaux 21*9e965d6fSRomain Jobredeauxdef _process( 22*9e965d6fSRomain Jobredeaux ctx, 23*9e965d6fSRomain Jobredeaux transitive_profiles = depset(), 24*9e965d6fSRomain Jobredeaux startup_profiles = [], 25*9e965d6fSRomain Jobredeaux deploy_jar = None, 26*9e965d6fSRomain Jobredeaux has_proguard_specs = False, 27*9e965d6fSRomain Jobredeaux enable_optimizer_integration = False, 28*9e965d6fSRomain Jobredeaux merge_tool = None, 29*9e965d6fSRomain Jobredeaux profgen = None, 30*9e965d6fSRomain Jobredeaux toolchain_type = None): 31*9e965d6fSRomain Jobredeaux """Processes all the transitive baseline profiles. 32*9e965d6fSRomain Jobredeaux 33*9e965d6fSRomain Jobredeaux Baseline profiles propagated from libraries will be merged, and if optimizer integration is 34*9e965d6fSRomain Jobredeaux enabled, startup profiles will be merged as well, and wildcards in baseline profiles will be 35*9e965d6fSRomain Jobredeaux expanded. 36*9e965d6fSRomain Jobredeaux 37*9e965d6fSRomain Jobredeaux Args: 38*9e965d6fSRomain Jobredeaux ctx: The context. 39*9e965d6fSRomain Jobredeaux transitive_profiles: Depset. The transitive baseline profiles propagated from android_library 40*9e965d6fSRomain Jobredeaux and aar_import. 41*9e965d6fSRomain Jobredeaux startup_profiles: List. The startup profiles. 42*9e965d6fSRomain Jobredeaux deploy_jar: File. The deploy jar. 43*9e965d6fSRomain Jobredeaux has_proguard_specs: Boolean. Whether to have proguard specs. 44*9e965d6fSRomain Jobredeaux enable_optimizer_integration: Boolean. Whether to use startup profile and baseline profiles in optimization. 45*9e965d6fSRomain Jobredeaux merge_tool: FilesToRunProvider. An executable for merging baseline profiles. 46*9e965d6fSRomain Jobredeaux profgen: FilesToRunProvider: An executable for compiling baseline profiles. 47*9e965d6fSRomain Jobredeaux toolchain_type: Label or String. Toolchain type of the executable used in actions. 48*9e965d6fSRomain Jobredeaux Returns: 49*9e965d6fSRomain Jobredeaux A struct containing all the outputs from processing baseline profiles. 50*9e965d6fSRomain Jobredeaux """ 51*9e965d6fSRomain Jobredeaux 52*9e965d6fSRomain Jobredeaux baseline_profile = None 53*9e965d6fSRomain Jobredeaux startup_profile = None 54*9e965d6fSRomain Jobredeaux if transitive_profiles: 55*9e965d6fSRomain Jobredeaux baseline_profile = _get_profile_artifact(ctx, "static-prof.txt") 56*9e965d6fSRomain Jobredeaux _merge( 57*9e965d6fSRomain Jobredeaux ctx, 58*9e965d6fSRomain Jobredeaux baseline_profile, 59*9e965d6fSRomain Jobredeaux transitive_profiles, 60*9e965d6fSRomain Jobredeaux "MergeBaselineProfiles", 61*9e965d6fSRomain Jobredeaux merge_tool = merge_tool, 62*9e965d6fSRomain Jobredeaux toolchain_type = toolchain_type, 63*9e965d6fSRomain Jobredeaux ) 64*9e965d6fSRomain Jobredeaux 65*9e965d6fSRomain Jobredeaux if has_proguard_specs and enable_optimizer_integration: 66*9e965d6fSRomain Jobredeaux # This is only needed for optimized builds since otherwise the dexer doesn't process this. 67*9e965d6fSRomain Jobredeaux if startup_profiles: 68*9e965d6fSRomain Jobredeaux startup_profile = _get_profile_artifact(ctx, "static-startup-prof.txt") 69*9e965d6fSRomain Jobredeaux _merge( 70*9e965d6fSRomain Jobredeaux ctx, 71*9e965d6fSRomain Jobredeaux output = startup_profile, 72*9e965d6fSRomain Jobredeaux inputs = ctx.files.startup_profiles, 73*9e965d6fSRomain Jobredeaux mnemonic = "MergeStartupProfiles", 74*9e965d6fSRomain Jobredeaux merge_tool = merge_tool, 75*9e965d6fSRomain Jobredeaux toolchain_type = toolchain_type, 76*9e965d6fSRomain Jobredeaux ) 77*9e965d6fSRomain Jobredeaux 78*9e965d6fSRomain Jobredeaux # Wildcards only need to be expanded for optimized builds since if these aren't consumed by 79*9e965d6fSRomain Jobredeaux # the optimizer, they can just be expanded during profile compilation instead. 80*9e965d6fSRomain Jobredeaux # Start-up profiles are not expanded because it shouldn't be necessary as these should 81*9e965d6fSRomain Jobredeaux # contain profiles generated by devices on start-up. 82*9e965d6fSRomain Jobredeaux if baseline_profile: 83*9e965d6fSRomain Jobredeaux expanded_baseline_profile = _get_profile_artifact(ctx, "expanded-static-prof.txt") 84*9e965d6fSRomain Jobredeaux _expand_wildcards( 85*9e965d6fSRomain Jobredeaux ctx, 86*9e965d6fSRomain Jobredeaux output = expanded_baseline_profile, 87*9e965d6fSRomain Jobredeaux deploy_jar = deploy_jar, 88*9e965d6fSRomain Jobredeaux profile = baseline_profile, 89*9e965d6fSRomain Jobredeaux profgen = profgen, 90*9e965d6fSRomain Jobredeaux toolchain_type = toolchain_type, 91*9e965d6fSRomain Jobredeaux ) 92*9e965d6fSRomain Jobredeaux baseline_profile = expanded_baseline_profile 93*9e965d6fSRomain Jobredeaux return struct( 94*9e965d6fSRomain Jobredeaux baseline_profile = baseline_profile, 95*9e965d6fSRomain Jobredeaux startup_profile = startup_profile, 96*9e965d6fSRomain Jobredeaux ) 97*9e965d6fSRomain Jobredeaux 98*9e965d6fSRomain Jobredeauxdef _process_art_profile( 99*9e965d6fSRomain Jobredeaux ctx, 100*9e965d6fSRomain Jobredeaux final_classes_dex, 101*9e965d6fSRomain Jobredeaux merged_profile, 102*9e965d6fSRomain Jobredeaux proguard_output_map = None, 103*9e965d6fSRomain Jobredeaux profgen = None, 104*9e965d6fSRomain Jobredeaux zipper = None, 105*9e965d6fSRomain Jobredeaux toolchain_type = None): 106*9e965d6fSRomain Jobredeaux """ Compiles the merged baseline profile. 107*9e965d6fSRomain Jobredeaux 108*9e965d6fSRomain Jobredeaux Profiles are compiled with profgen into binary ART profiles. The binary 109*9e965d6fSRomain Jobredeaux profiles will be bundled into the final APK and used at installation time to speed up app 110*9e965d6fSRomain Jobredeaux startup and reduce jank. 111*9e965d6fSRomain Jobredeaux 112*9e965d6fSRomain Jobredeaux Args: 113*9e965d6fSRomain Jobredeaux ctx: The context. 114*9e965d6fSRomain Jobredeaux final_classes_dex: File. Final classes zip artifact. 115*9e965d6fSRomain Jobredeaux merged_profile: File. The merged profile from transitive baseline profile files. 116*9e965d6fSRomain Jobredeaux proguard_output_map: File. Optional. The proguard output mapping file. 117*9e965d6fSRomain Jobredeaux profgen: FilesToRunProvider. The profgen executable for profile compilation. 118*9e965d6fSRomain Jobredeaux zipper: FilesToRunProvider. An executable for compressing files to an archive. 119*9e965d6fSRomain Jobredeaux toolchain_type: Label or String. Toolchain type of the executable used in actions. 120*9e965d6fSRomain Jobredeaux Returns: 121*9e965d6fSRomain Jobredeaux Provider info containing BaselineProfileProvider for all merged profiles. 122*9e965d6fSRomain Jobredeaux """ 123*9e965d6fSRomain Jobredeaux 124*9e965d6fSRomain Jobredeaux # Profgen 125*9e965d6fSRomain Jobredeaux output_profile = _get_profile_artifact(ctx, "baseline.prof") 126*9e965d6fSRomain Jobredeaux output_profile_meta = _get_profile_artifact(ctx, "baseline.profm") 127*9e965d6fSRomain Jobredeaux profgen_inputs = [final_classes_dex, merged_profile] 128*9e965d6fSRomain Jobredeaux profgen_args = ctx.actions.args() 129*9e965d6fSRomain Jobredeaux profgen_args.add("bin", merged_profile) 130*9e965d6fSRomain Jobredeaux profgen_args.add("--apk", final_classes_dex) 131*9e965d6fSRomain Jobredeaux profgen_args.add("--output", output_profile) 132*9e965d6fSRomain Jobredeaux profgen_args.add("--output-meta", output_profile_meta) 133*9e965d6fSRomain Jobredeaux if proguard_output_map: 134*9e965d6fSRomain Jobredeaux profgen_args.add("--map", proguard_output_map) 135*9e965d6fSRomain Jobredeaux profgen_inputs.append(proguard_output_map) 136*9e965d6fSRomain Jobredeaux ctx.actions.run( 137*9e965d6fSRomain Jobredeaux mnemonic = "GenerateARTProfile", 138*9e965d6fSRomain Jobredeaux executable = profgen, 139*9e965d6fSRomain Jobredeaux progress_message = "Generating Android P-R ART profile for %{label} APK", 140*9e965d6fSRomain Jobredeaux arguments = [profgen_args], 141*9e965d6fSRomain Jobredeaux inputs = profgen_inputs, 142*9e965d6fSRomain Jobredeaux outputs = [output_profile, output_profile_meta], 143*9e965d6fSRomain Jobredeaux use_default_shell_env = True, 144*9e965d6fSRomain Jobredeaux toolchain = toolchain_type, 145*9e965d6fSRomain Jobredeaux ) 146*9e965d6fSRomain Jobredeaux 147*9e965d6fSRomain Jobredeaux # Zip ART profiles 148*9e965d6fSRomain Jobredeaux output_profile_zip = _get_profile_artifact(ctx, "art_profile.zip") 149*9e965d6fSRomain Jobredeaux zip_args = ctx.actions.args() 150*9e965d6fSRomain Jobredeaux zip_args.add("c", output_profile_zip) 151*9e965d6fSRomain Jobredeaux zip_args.add(output_profile.path, format = "assets/dexopt/baseline.prof=%s") 152*9e965d6fSRomain Jobredeaux zip_args.add(output_profile_meta.path, format = "assets/dexopt/baseline.profm=%s") 153*9e965d6fSRomain Jobredeaux ctx.actions.run( 154*9e965d6fSRomain Jobredeaux mnemonic = "ZipARTProfiles", 155*9e965d6fSRomain Jobredeaux executable = zipper, 156*9e965d6fSRomain Jobredeaux progress_message = "Zip ART Profiles for %{label}", 157*9e965d6fSRomain Jobredeaux arguments = [zip_args], 158*9e965d6fSRomain Jobredeaux inputs = [output_profile, output_profile_meta], 159*9e965d6fSRomain Jobredeaux outputs = [output_profile_zip], 160*9e965d6fSRomain Jobredeaux use_default_shell_env = True, 161*9e965d6fSRomain Jobredeaux toolchain = toolchain_type, 162*9e965d6fSRomain Jobredeaux ) 163*9e965d6fSRomain Jobredeaux return BaselineProfileProvider( 164*9e965d6fSRomain Jobredeaux # Unnecessary to pass the transitive profiles to native rule 165*9e965d6fSRomain Jobredeaux depset(), 166*9e965d6fSRomain Jobredeaux output_profile_zip, 167*9e965d6fSRomain Jobredeaux ) 168*9e965d6fSRomain Jobredeaux 169*9e965d6fSRomain Jobredeauxdef _get_profile_dir(ctx): 170*9e965d6fSRomain Jobredeaux return ctx.label.name + _BASELINE_PROFILE_DIR_SUFFIX 171*9e965d6fSRomain Jobredeaux 172*9e965d6fSRomain Jobredeauxdef _get_profile_artifact(ctx, name): 173*9e965d6fSRomain Jobredeaux return ctx.actions.declare_file(_get_profile_dir(ctx) + name) 174*9e965d6fSRomain Jobredeaux 175*9e965d6fSRomain Jobredeauxdef _merge( 176*9e965d6fSRomain Jobredeaux ctx, 177*9e965d6fSRomain Jobredeaux output, 178*9e965d6fSRomain Jobredeaux inputs = [], 179*9e965d6fSRomain Jobredeaux mnemonic = "MergeBaselineProfiles", 180*9e965d6fSRomain Jobredeaux merge_tool = None, 181*9e965d6fSRomain Jobredeaux toolchain_type = None): 182*9e965d6fSRomain Jobredeaux args = ctx.actions.args() 183*9e965d6fSRomain Jobredeaux args.add_all(inputs, before_each = "--input") 184*9e965d6fSRomain Jobredeaux args.add("--output", output) 185*9e965d6fSRomain Jobredeaux 186*9e965d6fSRomain Jobredeaux ctx.actions.run( 187*9e965d6fSRomain Jobredeaux executable = merge_tool, 188*9e965d6fSRomain Jobredeaux mnemonic = mnemonic, 189*9e965d6fSRomain Jobredeaux arguments = [args], 190*9e965d6fSRomain Jobredeaux inputs = inputs, 191*9e965d6fSRomain Jobredeaux outputs = [output], 192*9e965d6fSRomain Jobredeaux use_default_shell_env = True, 193*9e965d6fSRomain Jobredeaux toolchain = toolchain_type, 194*9e965d6fSRomain Jobredeaux ) 195*9e965d6fSRomain Jobredeaux 196*9e965d6fSRomain Jobredeauxdef _expand_wildcards( 197*9e965d6fSRomain Jobredeaux ctx, 198*9e965d6fSRomain Jobredeaux output, 199*9e965d6fSRomain Jobredeaux deploy_jar = None, 200*9e965d6fSRomain Jobredeaux profile = None, 201*9e965d6fSRomain Jobredeaux profgen = None, 202*9e965d6fSRomain Jobredeaux toolchain_type = None): 203*9e965d6fSRomain Jobredeaux args = ctx.actions.args() 204*9e965d6fSRomain Jobredeaux args.add("expandWildcards", deploy_jar) 205*9e965d6fSRomain Jobredeaux args.add("--profile", profile) 206*9e965d6fSRomain Jobredeaux args.add("--output", output) 207*9e965d6fSRomain Jobredeaux 208*9e965d6fSRomain Jobredeaux ctx.actions.run( 209*9e965d6fSRomain Jobredeaux executable = profgen, 210*9e965d6fSRomain Jobredeaux outputs = [output], 211*9e965d6fSRomain Jobredeaux inputs = [deploy_jar, profile], 212*9e965d6fSRomain Jobredeaux arguments = [args], 213*9e965d6fSRomain Jobredeaux mnemonic = "ExpandBaselineProfileWildcards", 214*9e965d6fSRomain Jobredeaux progress_message = "Expanding baseline profile wildcards for %{label} APK", 215*9e965d6fSRomain Jobredeaux toolchain = toolchain_type, 216*9e965d6fSRomain Jobredeaux ) 217*9e965d6fSRomain Jobredeaux 218*9e965d6fSRomain Jobredeauxbaseline_profiles = struct( 219*9e965d6fSRomain Jobredeaux expand_wildcards = _expand_wildcards, 220*9e965d6fSRomain Jobredeaux get_profile_artifact = _get_profile_artifact, 221*9e965d6fSRomain Jobredeaux process = _process, 222*9e965d6fSRomain Jobredeaux process_art_profile = _process_art_profile, 223*9e965d6fSRomain Jobredeaux) 224